Lambda表達(dá)式中的異常-創(chuàng)新互聯(lián)

Java引入了已檢異常的概念。與早期的方法相比,強(qiáng)制開發(fā)人員管理異常的想法是革命性的。

創(chuàng)新互聯(lián)專注于網(wǎng)站建設(shè)|網(wǎng)站建設(shè)維護(hù)|優(yōu)化|托管以及網(wǎng)絡(luò)推廣,積累了大量的網(wǎng)站設(shè)計與制作經(jīng)驗(yàn),為許多企業(yè)提供了網(wǎng)站定制設(shè)計服務(wù),案例作品覆蓋成都玻璃隔斷等行業(yè)。能根據(jù)企業(yè)所處的行業(yè)與銷售的產(chǎn)品,結(jié)合品牌形象的塑造,量身開發(fā)品質(zhì)網(wǎng)站。

現(xiàn)在,Java仍然是唯一廣泛使用的提供已檢異常的語言。例如,Kotlin中的每個異常都是未檢查的。

即使在Java中,新特性也和已檢異常不一致:Java內(nèi)置函數(shù)式接口的簽名不使用異常。在lambda中集成遺留代碼時,代碼會變得很麻煩。這在溪流中很明顯。

在這篇文章中,我想深入探討如何管理這樣的問題。

代碼中的問題

下面的示例代碼說明了這個問題:

不能編譯:需要捕獲已檢查的ClassNotFoundException我們必須添加一個try/catch塊來修復(fù)編譯問題。

Stream.of("java.lang.String", "ch.frankel.blog.Dummy", "java.util.ArrayList")
      .map(it ->new ForNamer().apply(it))                                     // 1
? ? ? .forEach(System.out::println);

添加代碼塊違背了管道易于閱讀的目的。

將Try/Catch代碼塊封裝到一個類中?

為了恢復(fù)可讀性,我們需要重構(gòu)代碼以引入一個新類。IntelliJ IDEA甚至提出了一個記錄:?

var forNamer = new ForNamer();                                                // 1
Stream.of("java.lang.String", "ch.frankel.blog.Dummy", "java.util.ArrayList")
      .map(forNamer::apply)                                                   // 2
      .forEach(System.out::println);

record ForNamer() implements Function>{

    @Override
    public Classapply(String string) {
        try {
            return Class.forName(string);
        } catch (ClassNotFoundException e) {
            return null;
        }
    }
}
  1. 創(chuàng)建一個單獨(dú)的record對象。
  2. 重用它。
Trying With Lombok

項(xiàng)目Lombok是一個編譯時注釋處理器,它會生成額外的字節(jié)碼。使用正確的注釋就可以得到結(jié)果,而無需編寫樣板代碼。

  • Project Lombok是一個Java庫,它可以自動插入到您的編輯器和構(gòu)建工具中,為您的Java增添風(fēng)味。再也不要寫getter或equals方法了,只需一個注釋,你的類就有了功能齊全的構(gòu)建器,自動化你的日志記錄變量等等。

Lombok提供了@SneakyThrow注釋:它允許拋出已檢異常,而無需在方法簽名中聲明它們。然而,目前它并不適用于現(xiàn)有的API。

如果你是Lombok用戶,請注意,狀態(tài)停放有一個打開的GitHub問題。

Commons Lang 的救援

Apache Commons Lang是一個古老的項(xiàng)目。它在當(dāng)時很流行,因?yàn)樗峁┝艘恍┍究梢猿蔀镴ava API一部分的實(shí)用程序,但卻沒有。這比在每個項(xiàng)目中重新發(fā)明你的DateUtils和StringUtils要好得多。在研究這篇文章時,我發(fā)現(xiàn)它仍然使用很棒的api定期維護(hù)。其中之一是可失敗的API。?

該API由兩部分組成:

  1. 一個包裝器Stream
  2. 簽名接受異常的管道方法

這是一小段摘錄:

代碼最終變成了我們從一開始就期望的樣子:

Streamstream = Stream.of("java.lang.String", "ch.frankel.blog.Dummy", "java.util.ArrayList");
Failable.stream(stream)
        .map(Class::forName)                                                  // 1
? ? ? ? .forEach(System.out::println);
僅僅修復(fù)編譯時錯誤是不夠的

上述代碼在運(yùn)行時拋出ClassNotFoundException異常,并將其封裝在UndeclaredThrowableException中。我們滿足了編譯器的要求,但是我們沒有辦法指定預(yù)期的行為:

  • 處理第一個異常
  • 丟棄的異常
  • 聚合類和異常,以便我們可以在管道的最后階段對它們采取行動
  • 其他的東西

為了實(shí)現(xiàn)這一點(diǎn),我們可以利用Vavr的力量。Vavr是一個將函數(shù)式編程的強(qiáng)大功能引入Java語言的庫:

  • Vavr core是一個Java函數(shù)式庫。它有助于減少代碼量并提高健壯性。邁向函數(shù)式編程的第一步是從不可變值開始思考。Vavr提供了不可變集合以及操作這些值所需的函數(shù)和控制結(jié)構(gòu)。結(jié)果是美麗的,只是工作。

假設(shè)我們需要一個管道來收集異常和類。下面是該API的一個片段,描述了幾個構(gòu)建塊:

它翻譯成以下代碼:?

Stream.of("java.lang.String", "ch.frankel.blog.Dummy", "java.util.ArrayList")
      .map(CheckedFunction1.liftTry(Class::forName))                          // 1
      .map(Try::toEither)                                                     // 2
      .forEach(e ->{
          if (e.isLeft()) {                                                   // 3
              System.out.println("not found:" + e.getLeft().getMessage());
          } else {
              System.out.println("class:" + e.get().getName());
          }
? ? ? });
  1. 將這個調(diào)用封裝到一個Vavr Try中。
  2. 將Try轉(zhuǎn)換為Either,保留異常。如果我們不感興趣,可以使用Optional對象。
  3. 根據(jù)Either是否包含異常(左)或預(yù)期結(jié)果(右)來采取行動。?

到目前為止,我們都在Java流的世界里。它按預(yù)期工作,直到forEach,這看起來并不“漂亮”。

Vavr確實(shí)提供了自己的Stream類,它模仿了Java的Stream API并添加了額外的功能。讓我們用它來重寫管道:

var result = Stream.of("java.lang.String", "ch.frankel.blog.Dummy", "java.util.ArrayList")
        .map(CheckedFunction1.liftTry(Class::forName))
        .map(Try::toEither)
        .partition(Either::isLeft)                                              // 1
        .map1(left ->left.map(Either::getLeft))                                // 2
        .map2(right ->right.map(Either::get));                                 // 3

result._1().forEach(it ->System.out.println("not found: " + it.getMessage())); // 4
result._2().forEach(it ->System.out.println("class: " + it.getName())); ? ? ? ?// 4
  1. 將Either的流劃分為兩個流組成的元組。
  2. 將左邊的流從任一流壓平,變成可拋擲的流。
  3. 將右邊的stream從Either的stream展平為Class的stream。
  4. 想做什么就做什么。?
結(jié)論

Java最初的設(shè)計大量使用了已檢異常。編程語言的發(fā)展證明了這不是一個好主意。

Java流不能很好地處理已檢異常。將后者集成到前者所需的代碼看起來并不好。為了恢復(fù)流的可讀性,我們可以使用Apache Commons Lang。

編譯只是問題的一小部分。我們通常希望對異常采取行動,而不是停止管道或忽略異常。在這種情況下,我們可以利用Vavr庫,它提供了一種更函數(shù)式的方法。

你是否還在尋找穩(wěn)定的海外服務(wù)器提供商?創(chuàng)新互聯(lián)www.cdcxhl.cn海外機(jī)房具備T級流量清洗系統(tǒng)配攻擊溯源,準(zhǔn)確流量調(diào)度確保服務(wù)器高可用性,企業(yè)級服務(wù)器適合批量采購,新人活動首月15元起,快前往官網(wǎng)查看詳情吧

分享題目:Lambda表達(dá)式中的異常-創(chuàng)新互聯(lián)
網(wǎng)站路徑:http://muchs.cn/article48/dgepep.html

成都網(wǎng)站建設(shè)公司_創(chuàng)新互聯(lián),為您提供微信小程序、企業(yè)網(wǎng)站制作、網(wǎng)站營銷、Google、云服務(wù)器、小程序開發(fā)

廣告

聲明:本網(wǎng)站發(fā)布的內(nèi)容(圖片、視頻和文字)以用戶投稿、用戶轉(zhuǎn)載內(nèi)容為主,如果涉及侵權(quán)請盡快告知,我們將會在第一時間刪除。文章觀點(diǎn)不代表本網(wǎng)站立場,如需處理請聯(lián)系客服。電話:028-86922220;郵箱:631063699@qq.com。內(nèi)容未經(jīng)允許不得轉(zhuǎn)載,或轉(zhuǎn)載時需注明來源: 創(chuàng)新互聯(lián)

h5響應(yīng)式網(wǎng)站建設(shè)