Java中v函数_Java函数式编程类库-Vavr

对于无法在工作中使用Scala和kotlin开发的人,Vavr是一个很好的折中的方案,提供了持久的数据类型和功能控制结构。这里对Vavr里面的常用模块做一些简单的介绍,需要详细了解的请去官网查看文档(https://www.vavr.io/vavr-docs/)。

vavr支持多种数据结构,弥补了常见collection的不足,扩展了数据集合的操作方式。

1600e5f5316b91ee8f6e7e576dafe974.png

一、支持不可变的数据结构

对于多线程的操作,不同线程异步对共享数据的修改会存在一定的风险,稍不留意可能导致数据的错误。而不可变数据集合,避免了对数据的修改,减少了多线程修改数据导致错误的可能性。同时通过map和flatMap又完美的实现了数据的转换,代替了修改操作。

@Testpublic voidtest() {

java.util.List otherList = new ArrayList<>();

java.util.List list =Collections.unmodifiableList(otherList);/*** 这里会抛出 UnsupportedOperationException

* Collections.unmodifiableListN 返回的是

* java.util.Collections.UnmodifiableList#UnmodifiableList*/list.add("a");//通过 map实现对数据的修改

List listNew = list.parallelStream().map(i -> i +"--").collect(Collectors.toList());

}

Collections.unmodifiableList返回的是一个UnmodifiableList的子类,而该方法中所对元素进行增加/删除的操作进行了屏蔽.

9a3282f961b343c1f2c1995f9722d164.png

list 的一些简单操作

//指定元素数量

List list1 =List.of(1,2,3,4);//循环10次填充1

List list2 =List.fill(10,1);//填充1-> 100 的数据

List list3 = List.range(1,100);//指定步长为20

List list4 = List.rangeBy(1,100,20);//vavr List 转换为 java list

java.util.List list5 =list4.asJava();//list5.add("A");//不可变list,无法添加元素//转变为可变list,

java.util.List list6 =list4.asJavaMutable();

list6.add("A");int a = list1.map(i -> (i * 10)).flatMap(i-> List.fill(i,i)).foldLeft(0,(m,n)->m + n); //3000

执行结果:

85ed911f1c41368ab86ecace7893d729.png

二,支持元组

Java里面的方法是无法返回具有不同元素的集合的,同时也无法像Python一样返回多个参数。但在某些场景下,有时候需要返回多个不同类型的结果值。此时对于Java就又如下几种方案:1、把结果放在 Collection中返回;2、封装一个Java对象,把结果当做对象的参数返回;3、用Object [] 数组来存储不同的类型数据。而Vavr借鉴了Scala里面的元组Tuple类型,支持封装多个不同类型结果。

Tuple0 entry0 =Tuple.empty();

Tuple1 entry1 = Tuple.of(1);

Tuple2 entry2 = Tuple.of(1, "A");

Tuple3 entry3 = Tuple.of(1, "A", newA());//entry3._1 = 1//entry3._2 = "A"//entry3._1 = A()//通过map实现了类型的转换

Tuple2 newTuple2 = entry2.map( s -> "s = "+s, i -> (int)(i.charAt(0)));

元组的类型为Tuple0,Tuple1,Tuple2,Tuple3等。当前有8个元素的上限。要访问元组的元素t,可以使用方法t._1访问第一个元素,t._2访问第二个元素,依此类推。

三、函数的操作

对于函数式编程,最重要的就是函数的组合,函数作为第一公民,可以当做变量和参数进行传递和调用。在vavr中同样是支持了andThen、compose等。

Function1 plusOne = a -> a + 1;

Function1 multiplyByTwo = a -> a * 2;

Function1 add1AndMultiplyBy2 =plusOne.andThen(multiplyByTwo);

Integer result= add1AndMultiplyBy2.apply(2); //result = 6

Function1 add1AndMultiplyBy3 =multiplyByTwo.compose(plusOne);

add1AndMultiplyBy3.apply(2);

同样,对于柯里化,vavr也是支持的。通过柯里化,可以减少函数的入参。

//三个入参

Function3 sum = (a, b, c) -> a + b *c;//转换为两个入参,a默认设置为2

final Function1> add2 = sum.curried().apply(2);//转换为一个参数,a默认为2. 此时 mulit3 = (c) -> 2 + 3 * c

final Function1 mulit3 = add2.curried().apply(3);

Integer result= mulit3.apply(5); //17

四、记忆化

记忆化是缓存的一种形式。记忆功能仅执行一次,然后从缓存返回结果。

下面的示例在第一次调用时计算一个随机数,并在第二次调用时返回缓存的数字。

Function0 hashCache =Function0.of(Math::random).memoized();double randomValue1 = hashCache.apply(); //首次触发生成 hashCache

double randomValue2 = hashCache.apply(); //第二次调用时返回第一次生成的 hashCache

System.out.printf(String.valueOf(randomValue1 - randomValue2)); //0.0

五、对Option 进行支持

Option使用的场景还是比较多的,为了避免NPE的情况,通过Option可以对null值进行包装,返回empty或者None对象,减少了在代码中通过 if(value == null)的判断逻辑。

//java 的 Optional

Optional javaMaybeFoo = Optional.of("foo");

Optional javaMaybeFooBar = javaMaybeFoo.map(s -> (String)null)

.map(s-> s.toUpperCase() + "bar");

System.out.println(javaMaybeFooBar);//Optional.empty//vavr 同样支持 Option,这里的Option和Scala的Option几乎一模一样

Option maybeFoo = Option.of("foo");

Option maybeFooBar = maybeFoo.flatMap(s -> Option.of((String)null))

.map(s-> s.toUpperCase() + "bar");

System.out.println(maybeFooBar);//None

六、Try对异常的处理

在Java中,如果发生异常且未进行捕获,则当前线程就会被中断,后续的调用就会停止。而Java中通过try{}catch(){}对可能出现异常的代码块进行捕获,保证了发生异常之后能够进行有效的处理,且顺利的执行完余下的工作。但问题是通过大量的try{}catch代码块看起来较为臃肿。vavr中通过Try类型则很好的解决了try{}catch的臃肿问题。

Try result = Try.of(() -> 0)

.map((a)-> 10 / a) //即使此处抛出异常,不会导致当前线程结束。这里无需使用 try{}catch()对代码进行捕获

.andThen(() -> System.out.printf("--抛出异常此处不会执行--")) //执行一个动作,不修改结果

.map(i ->{

System.out.println("当前值:" +i);return i + 10;

})

.onFailure(e-> e.printStackTrace())//失败时会触发onFailure

.recover(ArithmeticException.class, 1000) //如果遇到 Exception类型的异常,则返回1000

.map((a) -> a + 1);

System.out.println("是否抛出异常:" +result.isFailure());

System.out.println("执行结果:" + result.getOrElse(100)); //如果有异常发生,则返回100

七、延迟计算Lazy

Lazy 类型数据在不进行get前是不会触发计算的,只有在调用get方法时,才会触发整个流程的计算,起到延迟计算的作用。

Lazy lazy =Lazy.of(Math::random)

.map(i->{

System.out.println("-----正在进行计算,此处只会执行一次------");return i * 100;

});

System.out.println(lazy.isEvaluated());

System.out.println(lazy.get());//触发计算

System.out.println(lazy.isEvaluated());

System.out.println(lazy.get());//不会重新计算,返回上次结果

八、线程利器Future

vavr通过Future简化了线程的使用方式,不用再像Java异常进行创建Callable,无需进行submit,直接创建一个Future对象即可。Future提供的所有操作都是非阻塞的,其底层的ExecutorService用于执行异步处理程序

System.out.println("当前线程名称:" +Thread.currentThread().getName());

Integer result= Future.of(() ->{

System.out.println("future线程名称:" +Thread.currentThread().getName());

Thread.sleep(2000);return 100;

})

.map(i-> i * 10)

.await(3000, TimeUnit.MILLISECONDS) //等待线程执行3000毫秒

.onFailure(e ->e.printStackTrace())

.getValue()//返回Optional>类型结果

.getOrElse(Try.of(() -> 100)) //如果Option 为 empty时,则返回Try(100)

.get();

System.out.println(result);//1000

执行结果:

当前线程名称:main

future线程名称:ForkJoinPool.commonPool-worker-1

1000

九、减少if else的模式匹配

Java的switch case是具有很大的局限性的,仅仅对简单的基本类型进行了支持,而对于包装类型是无法使用的。而在Scala中是支持各种类型的模式匹配,不仅如此,其还具有对象解构、前置条件,守卫,而vavr支持了这些功能。

vavr中用$表达不同的匹配模式。

$()-通配符模式

$(value)-等于模式

$(predicate)-条件模式

int i = 1;

String s=Match(i).of(

Case($(1), "one"), //等值匹配

Case($(2), "two"),

Case($(),"?")

);

String b=Match(i).of(

Case($(is(1)), "one"), //谓词表达式匹配

Case($(is(2)), "two"),

Case($(),"?")

);

String arg= "-h";

Match(arg).of(

Case($(isIn("-h", "--help")), o -> run(this::displayHelp)), //支持在成功匹配后执行动作

Case($(isIn("-v", "--version")), o -> run(this::displayVersion)),

Case($(), o-> run(() ->{throw newIllegalArgumentException(arg);

}))

);

A obj= newA();

Number plusOne=Match(obj).of(

Case($(instanceOf(Integer.class)), i -> i + 1), //根据值类型进行匹配

Case($(instanceOf(Double.class)), d -> d + 1),

Case($(), o-> { throw newNumberFormatException(); })

);

Tuple2 tuple2= Tuple("a",2);

Try> _try =Try.success(tuple2);

Match(_try).of(

Case($Success($Tuple2($("a"), $())), tuple22 ->{}),

Case($Failure($(instanceOf(Error.class))), error ->error.fillInStackTrace())

);

Option option= Option.some(1);

Match(option).of(

Case($Some($()),"defined"),

Case($None(),"empty")

);

除了上面比较常用的数据类型,vavr还有其他各种便捷的数据结构,感兴趣的可以深入了解一下。

=========================================

=========================================

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值