<kbd id="afajh"><form id="afajh"></form></kbd>
<strong id="afajh"><dl id="afajh"></dl></strong>
    <del id="afajh"><form id="afajh"></form></del>
        1. <th id="afajh"><progress id="afajh"></progress></th>
          <b id="afajh"><abbr id="afajh"></abbr></b>
          <th id="afajh"><progress id="afajh"></progress></th>

          這個(gè)類(lèi)庫(kù)可以幫助你理解Java中的函數(shù)式編程

          共 6811字,需瀏覽 14分鐘

           ·

          2021-06-23 23:09

          每當(dāng)JDK發(fā)布了新版本就有同學(xué)說(shuō)“你發(fā)任你發(fā),我用Java 8”,可在工作中有不少人依然不太擅長(zhǎng)使用Java8的新特性,而這些特性往往讓Java不再“臃腫”。不過(guò)我個(gè)人認(rèn)為Java8所有的新特性中最具有代表性的一定是函數(shù)式編程。有人會(huì)說(shuō)這種風(fēng)格太抽象難懂了,當(dāng)你熟練掌握這種設(shè)定之后,你一定會(huì)感到很香。慢慢地你也會(huì)領(lǐng)會(huì)到函數(shù)式編程的魅力和精髓。今天介紹一個(gè)函數(shù)式Java工具包,它表現(xiàn)了很多優(yōu)秀的函數(shù)式編程思想。以前介紹的熔斷降級(jí)組件Hystrix的替代品resilience4j就基于vavr庫(kù)。

          Vavr

          Vavr是一個(gè)Java8函數(shù)庫(kù),它運(yùn)用了大量的函數(shù)式編程范式。創(chuàng)造性地封裝了一些持久性的數(shù)據(jù)結(jié)構(gòu)和函數(shù)式控制結(jié)構(gòu)。而且從中可以學(xué)到很多有用的編程思想。

          可觀察的副作用

          我們的代碼中經(jīng)常會(huì)出現(xiàn)一些看不見(jiàn)的陷阱,從代碼語(yǔ)義中這些陷阱是無(wú)法被觀察的。例如

          int divide(int a, int b){
           return a/b;
          }

          我們知道a/b會(huì)得到一個(gè)整數(shù),但是卻不能從代碼上明確地知道如果b=0將會(huì)拋出java.lang.ArithmeticException異常;而如果是a+b則不會(huì)帶來(lái)任何副作用。所以我們需要讓這種副作用是可觀察的。對(duì)于這一點(diǎn)Vavr做出了一種設(shè)計(jì):

          Try<Integer> divide(Integer a, Integer b) {
              return Try.of(() -> a / b);
          }

          將可能的副作用封裝到一個(gè)容器中,明確了可能的失敗,當(dāng)你看到返回的是Try<Integer>時(shí),就意味著結(jié)果可能“并不順利”,以便于針對(duì)性地進(jìn)行預(yù)防。

          不可變的數(shù)據(jù)結(jié)構(gòu)

          很多語(yǔ)言都在使用不可變的數(shù)據(jù)結(jié)構(gòu),比如Golang、Kotlin。主要原因是不可變的值:

          • 本質(zhì)上是線(xiàn)程安全的,因此不需要同步
          • 對(duì)于equalshashCode是可靠的
          • 不需要克隆
          • 在非受檢unchecked類(lèi)型轉(zhuǎn)換中是類(lèi)型安全的
          • 對(duì)于函數(shù)式編程來(lái)說(shuō)不可變值是最透明的

          為此Vavr設(shè)計(jì)了一個(gè)集合類(lèi)庫(kù),旨在代替Java中的集合框架。Vavr 的集合庫(kù)包含一組豐富的函數(shù)式數(shù)據(jù)結(jié)構(gòu),這些數(shù)據(jù)結(jié)構(gòu)建立在 lambdas 之上。它們與 Java 原始集合共享的唯一接口是Iterable。這些數(shù)據(jù)結(jié)構(gòu)是持久性的,一旦初始化本身就不可改變,你可以使用一些操作來(lái)返回更改后的副本。例如經(jīng)典的數(shù)據(jù)結(jié)構(gòu)單向鏈表:

          // 1   2  3
          List<Integer> source = List.of(123);

          如果我們將一個(gè)新元素0放在原始鏈表尾部的前面

          //  0  2  3
          List<Integer> newHeadList = source.tail().prepend(0);
          //  1  2  3
          System.out.println(source);

          原始鏈表保持不變,新的鏈表大小保持不變?cè)乇惶鎿Q了。當(dāng)然你可以使用其它API來(lái)生成一個(gè)大小變化的副本,不過(guò)可以肯定的是原始的鏈表一定不會(huì)發(fā)生改變。

          // 0 1 2 3
          List<Integer> prepend = source.prepend(0);
          // 1 2 3 0
          List<Integer> append = source.append(0);

          這只是其中的一部分編程思想,接下來(lái)我將介紹Vavr的一些特色。

          Vavr的一些特色

          Vavr提供了一些非常有用的而且有特色的API。

          元組

          熟悉Python的同學(xué)對(duì)元組(Tuple)一定不陌生。元組將固定數(shù)量的元素組合在一起,以便它們可以作為一個(gè)整體傳遞。與數(shù)組或列表不同,元組可以包含不同類(lèi)型的對(duì)象,但它也是不可變的。目前Vavr提供了最多8個(gè)元素的元組結(jié)構(gòu)。

          // (felord.cn, 22)
          Tuple2<String, Integer> java8 = Tuple.of("felord.cn"22); 
          // felord.cn
          String s = java8._1; 
          // 22
          Integer i = java8._2;

          ?

          這個(gè)可以用來(lái)模擬Java中不具有的多返回值的特性。

          Function

          Java本身提供了Function接口,但是Vavr則提供了更加豐富的Function擴(kuò)展,例如可以組合多個(gè)Function

          Function1<Integer, Integer> multiplyByTwo = a -> a * 2;
          Function1<Integer, Integer> compose = multiplyByTwo.compose(a -> a + 1);
          // 6
          Integer apply = compose.apply(2);

          除此之外,還可以讓潛在的副作用降級(jí)(lift),有點(diǎn)類(lèi)似于微服務(wù)的熔斷,以避免在函數(shù)執(zhí)行中處理異常

          Function2<Integer, Integer, Integer> divide = (a, b) -> a / b;
          // 降級(jí) 
          Function2<Integer, Integer, Option<Integer>> safeDivide = Function2.lift(divide);
          // 返回一個(gè)加強(qiáng)版的Optional
          Option<Integer> apply = safeDivide.apply(10);
          boolean empty = apply.isEmpty();
          // true
          System.out.println(empty);

          還有派生操作:

           Function2<Integer, Integer, Integer> divide = (a, b) -> a / b;
           Function1<Integer, Integer> a = divide.apply(4);
           Integer apply = a.apply(2);

          這有點(diǎn)類(lèi)似于柯里化,當(dāng)我們用到更多入?yún)r(shí)柯里化才更加明顯:

          Function3<Integer, Integer, Integer, Integer> sum = (a, b, c) -> a + b + c;
          final Function1<Integer, Function1<Integer, Integer>> add2 = sum.curried().apply(1);
          Integer apply = add2.apply(2).apply(3);

          ?

          猜一猜答案是幾?

          帶有特性的值容器

          這個(gè)不太好用中文說(shuō)明,有一些值帶有獨(dú)特的性質(zhì),比如開(kāi)頭提到的Try,用來(lái)顯式表明可能遇到異常。Vavr提供了很多具有獨(dú)特性質(zhì)的值容器。

          Option

          類(lèi)似Optional,但是比Optional更加強(qiáng)大。

          Lazy

          Lazy是一個(gè)惰性計(jì)算的容器,表示當(dāng)使用時(shí)才去計(jì)算且只計(jì)算一次。

          Lazy<Double> lazy = Lazy.of(Math::random);
          lazy.isEvaluated(); // = false
          lazy.get();         // = 0.123  
          lazy.isEvaluated(); // = true
          lazy.get();         // = 0.123 
          // 需要使用數(shù)據(jù)時(shí)才從數(shù)據(jù)源加載
          Data lazyData = Lazy.val(DataSourceService::get, Data.class);

          其它還有一些非常有用的容器,你可以嘗試它們。

          模式匹配

          函數(shù)式編程語(yǔ)言大都支持模式匹配,同為JVM語(yǔ)言的Scala中就有這種特性,而Java目前是沒(méi)有的??梢杂行У貛椭覀儨p少if-else,舉個(gè)例子:

             public static String convert(int input) {

                  String output;
                  if (input == 1) {
                      output = "one";
                  } else if (input == 2) {
                      output = "two";
                  } else if (input == 3) {
                      output = "three";
                  } else {
                      output = "unknown";
                  }
                  return output;
              }

          你就說(shuō)吧,繞不繞?,Vavr就清爽多了。

              public static String vavrMatch(int input) {
                  return Match(input).of(
                          Case($(1), "one"),
                          Case($(2), "two"),
                          Case($(3), "three"),
                          Case($(), "unknown")
                  );
              }

          當(dāng)然還有其它一些玩法需要你自己去發(fā)現(xiàn)。

          總結(jié)

          函數(shù)式編程作為Java8最大的一個(gè)亮點(diǎn)(個(gè)人認(rèn)為),對(duì)于習(xí)慣于傳統(tǒng)OOP編程的開(kāi)發(fā)者來(lái)說(shuō)確實(shí)不容易接受。你不妨從Vavr類(lèi)庫(kù)入手去學(xué)習(xí)函數(shù)式編程的思想。今天介紹的只是它很少的一部分,還有更多等著你去發(fā)現(xiàn)、去借鑒。忘記說(shuō)了,如果你想在項(xiàng)目中引用它,可以引入下面這個(gè)坐標(biāo):

          <!-- https://mvnrepository.com/artifact/io.vavr/vavr -->
          <dependency>
              <groupId>io.vavr</groupId>
              <artifactId>vavr</artifactId>
              <version>0.10.3</version>
          </dependency>

          往期推薦

          Java17 新特性確定,Java之父:終于可以和一個(gè)長(zhǎng)達(dá)25年的漏洞說(shuō)再見(jiàn)了

          是時(shí)候轉(zhuǎn)型 Serverless 來(lái)玩微服務(wù)了嗎?

          還在用Jenkins?看看這些替代方案,是否更適合你!

          Spring 面試題(2021最新版)趕緊收藏!

          因一次騎行的臉剎著地,誕生了自動(dòng)駕駛自行車(chē)!不愧是野生鋼鐵俠!太硬核了~~~



          點(diǎn)下方卡片,關(guān)注作者:碼農(nóng)小胖哥

          分享高質(zhì)量編程知識(shí),探討IT人生

          瀏覽 50
          點(diǎn)贊
          評(píng)論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          評(píng)論
          圖片
          表情
          推薦
          點(diǎn)贊
          評(píng)論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          <kbd id="afajh"><form id="afajh"></form></kbd>
          <strong id="afajh"><dl id="afajh"></dl></strong>
            <del id="afajh"><form id="afajh"></form></del>
                1. <th id="afajh"><progress id="afajh"></progress></th>
                  <b id="afajh"><abbr id="afajh"></abbr></b>
                  <th id="afajh"><progress id="afajh"></progress></th>
                  欧美性爱综合在线 | 国产三四区,婷婷 | 91亚洲国产成人久久精品麻豆 | 日本三级视频中文字幕 | 影音先锋成人无码影院 |