成人国产在线小视频_日韩寡妇人妻调教在线播放_色成人www永久在线观看_2018国产精品久久_亚洲欧美高清在线30p_亚洲少妇综合一区_黄色在线播放国产_亚洲另类技巧小说校园_国产主播xx日韩_a级毛片在线免费

資訊專欄INFORMATION COLUMN

Java8(1):當(dāng) Lambda 遇上受檢異常

lavor / 2809人閱讀

摘要:如果的流式操作中多幾個(gè)需要拋出受檢異常的情況,那代碼真是太不直觀了,所以為了的,我們需要解決的辦法。不過既然受檢異常已經(jīng)是中的客觀存在的事物,所謂道高一尺,魔高一丈總是會(huì)有辦法來應(yīng)對(duì)。

我今天高高興興,想寫個(gè)簡單的統(tǒng)計(jì)一個(gè)項(xiàng)目下有多少行代碼的小程序,于是咔咔的寫下:

long count = Files.walk(Paths.get("D:/Test"))                      // 獲得項(xiàng)目目錄下的所有目錄及文件
                .filter(file -> !Files.isDirectory(file))          // 篩選出文件
                .filter(file -> file.toString().endsWith(".java")) // 篩選出 java 文件
                .flatMap(file -> Files.lines(file))                // 按行獲得文件中的文本
                .filter(line -> !line.trim().isEmpty())            // 過濾掉空行
                .count();

System.out.println("代碼行數(shù):" + count);

{ 題外話開始:

Files.walk(Path) 在 JDK1.8 時(shí)添加,深度優(yōu)先遍歷一個(gè) Path (目錄),返回這個(gè)目錄下所有的 Path(目錄和文件),通過 Stream 返回;

Files.lines(Path) 也是在 JDK1.8 時(shí)添加,功能是返回指定 Path (文件)中所有的行,通過 Stream 返回

題外話結(jié)束 }

然后,編譯不過 —— 因?yàn)?Files.lines(Path) 會(huì)拋出 IOException,如果要編譯通過,得這樣寫:

long count = Files.walk(Paths.get("D:/Test"))                      // 獲得項(xiàng)目目錄下的所有文件
                .filter(file -> !Files.isDirectory(file))          // 篩選出文件
                .filter(file -> file.toString().endsWith(".java")) // 篩選出 java 文件
                .flatMap(file -> {
                    try {
                        return Files.lines(file);
                    } catch (IOException ex) {
                        ex.printStackTrace(System.err);
                        return Stream.empty();                     // 拋出異常時(shí)返回一個(gè)空的 Stream
                    }
                })                                                 // 按行獲得文件中的文本
                .filter(line -> !line.trim().isEmpty())            // 過濾掉空行
                .count();

System.out.println("代碼行數(shù):" + count);

我的天,這個(gè)時(shí)候我強(qiáng)迫癥就犯了 —— 因?yàn)檫@樣的 Lambda 不是 one-liner expression,不夠簡潔。如果 Stream 的流式操作中多幾個(gè)需要拋出受檢異常的情況,那代碼真是太不直觀了,所以為了 one-liner expression 的 Lambda,我們需要解決的辦法。

解決方法1:通過新建一個(gè)方法(:) 無奈但是純潔的微笑)

public static void main(String[] args) throws Exception {
    long count = Files.walk(Paths.get("D:/Test"))                       // 獲得項(xiàng)目目錄下的所有文件
                    .filter(file -> !Files.isDirectory(file))           // 篩選出文件
                    .filter(file -> file.toString().endsWith(".java"))  // 篩選出 java 文件
                    .flatMap(file -> getLines(file))                    // 按行獲得文件中的文本
                    .filter(line -> !line.trim().isEmpty())             // 過濾掉空行
                    .count();

    System.out.println("代碼行數(shù):" + count);
}

private static Stream getLines(Path file) {
    try {
        return Files.lines(file);
    } catch (IOException ex) {
        ex.printStackTrace(System.err);
        return Stream.empty();
    }
}

這種解決方法下,我們需要處理受檢異常 —— 即在程序拋出異常的時(shí)候,我們需要告訴程序怎么去做(getLines 方法中拋出異常時(shí)我們輸出了異常,并返回一個(gè)空的 Stream

解決方法2:將會(huì)拋出異常的函數(shù)進(jìn)行包裝,使其不拋出受檢異常

如果一個(gè) FunctionInterface 的方法會(huì)拋出受檢異常(比如 Exception),那么該 FunctionInterface 便可以作為會(huì)拋出受檢異常的 Lambda 的目標(biāo)類型。

我們定義如下一個(gè) FunctionInterface

@FunctionalInterface
interface UncheckedFunction {
    R apply(T t) throws Exception;
}

那么該 FunctionInterface 便可以作為類似于 file -> File.lines(file) 這類會(huì)拋出受檢異常的 Lambda 的目標(biāo)類型,此時(shí) Lambda 中并不需要捕獲異常(因?yàn)槟繕?biāo)類型的 apply 方法已經(jīng)將異常拋出了)—— 之所以原來的 Lambda 需要捕獲異常,就是因?yàn)樵诹魇讲僮?flatMap 中使用的 java.util.function 包下的 Function 沒有拋出異常:

那我們?nèi)绾问褂?UncheckedFunction 到流式操作的 Lambda 中呢?
首先我們定義一個(gè) Try 類,它的 of 方法提供將 UncheckedFunction 包裝為 Function 的功能:

public class Try {

    public static  Function of(UncheckedFunction mapper) {
        Objects.requireNonNull(mapper);
        return t -> {
            try {
                return mapper.apply(t);
            } catch (Exception ex) {
                throw new RuntimeException(ex);
            }
        };
    }

    @FunctionalInterface
    public static interface UncheckedFunction {

        R apply(T t) throws Exception;
    }
}

然后在原先的代碼中,我們使用 Try.of 方法來對(duì)會(huì)拋出受檢異常的 Lambda 進(jìn)行包裝:

long count = Files.walk(Paths.get("D:/Test"))              // 獲得項(xiàng)目目錄下的所有文件
                .filter(file -> !Files.isDirectory(file))          // 篩選出文件
                .filter(file -> file.toString().endsWith(".java")) // 篩選出 java 文件
        
                .flatMap(Try.of(file -> Files.lines(file)))        // 將 會(huì)拋出受檢異常的 Lambda 包裝為 拋出非受檢異常的 Lambda
        
                .filter(line -> !line.trim().isEmpty())            // 過濾掉空行
                .count();

System.out.println("代碼行數(shù):" + count);

此時(shí),我們便可以選擇是否去捕獲異常(RuntimeException)。這種解決方法下,我們一般不關(guān)心拋出異常的情況 —— 比如自己寫的小例子,拋出了異常程序就該終止;或者你知道這個(gè) Lambda 確實(shí) 100% 不會(huì)拋出異常。

我更傾向于一種指定默認(rèn)值的包裝方法,即如果拋出異常,那么就返回默認(rèn)值:

public static  Function of(
        UncheckedFunction mapper, R defaultR) {
    Objects.requireNonNull(mapper);
    return t -> {
        try {
            return mapper.apply(t);
        } catch (Exception ex) {
            System.err.println(ex.getMessage());
            return defaultR;
        }
    };
}

比如我們前面的例子,如果 file -> Files.lines(file) 拋出異常了,說明在訪問 file 類的時(shí)候出了問題,我們可以就假設(shè)這個(gè)文件的行數(shù)為 0 ,那么默認(rèn)值就是個(gè)空的 Stream

long count = Files.walk(Paths.get("D:/Test"))              // 獲得項(xiàng)目目錄下的所有文件
                .filter(file -> !Files.isDirectory(file))          // 篩選出文件
                .filter(file -> file.toString().endsWith(".java")) // 篩選出 java 文件
        
                .flatMap(Try.of(file -> Files.lines(file), Stream.empty()))
        
                .filter(line -> !line.trim().isEmpty())            // 過濾掉空行
                .count();

System.out.println("代碼行數(shù):" + count);

使用 UncheckedFunction 這種方式更為通用,我們可以在更多的地方將 UncheckedFunction 包裝成 java.util.function.Function。類似的,我們可以包裝 UncheckedConsumerjava.util.function.Consumer,包裝 UncheckedSupplierSuppiler,UncheckedBiFunctionBiFunction 等。

就我個(gè)人觀點(diǎn)而言,我真的不喜歡 Java 中的受檢(Checked)異常,我認(rèn)為所有的異常都應(yīng)該是非受檢(Unchecked)的 —— 因?yàn)橐欢未a如果會(huì)產(chǎn)生異常,我們自然會(huì)去解決這個(gè)問題直到其不拋出異?;蛘卟东@這個(gè)異常并做對(duì)應(yīng)處理 —— 強(qiáng)制性的要求編碼人員捕獲異常,帶來的更多的是編碼上的不方便和代碼可讀性的降低(因?yàn)槿哂啵?。不過既然受檢異常已經(jīng)是 Java 中的客觀存在的事物,所謂“道高一尺,魔高一丈” —— 總是會(huì)有辦法來應(yīng)對(duì)。

文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。

轉(zhuǎn)載請(qǐng)注明本文地址:http://systransis.cn/yun/66363.html

相關(guān)文章

  • Introducing FP in Java8

    摘要:函數(shù)副作用會(huì)給程序設(shè)計(jì)帶來不必要的麻煩,引入潛在的,并降低程序的可讀性。所以只能采用這種曲線救國的方式。則是把這種曲線救國拿到了臺(tái)面上,并昭告天下,同時(shí)還對(duì)提供了一些語法支持。是自由變量,提供執(zhí)行上下文,觸發(fā)閉包執(zhí)行。 背景 自從2013年放棄了Java就再也沒有碰過。期間Java還發(fā)布了重大更新:引入lambda,但是那會(huì)兒我已經(jīng)玩了一段時(shí)間Scala,對(duì)Java已經(jīng)瞧不上眼。相比S...

    Prasanta 評(píng)論0 收藏0
  • Jumping with Try

    摘要:解決思路或生產(chǎn)對(duì)象,扮演生產(chǎn)者的角色而消費(fèi)對(duì)象,扮演消費(fèi)者的角色。正常情況下它們生產(chǎn)對(duì)象,而異常情況下,則拋出異常。重構(gòu)的思路在于將異常處理更加明晰化,讓生產(chǎn)者與消費(fèi)者之間的關(guān)系流水化。容器化其中,與包內(nèi)私有,對(duì)外不公開。 場(chǎng)景 以一個(gè)簡化了的用戶登錄的鑒權(quán)流程,流程大體如下: 首先嘗試本站鑒權(quán),如果失敗,再嘗試twiter的方式恢復(fù); 之后再進(jìn)行Two Factor認(rèn)證; 快速實(shí)...

    Java3y 評(píng)論0 收藏0
  • Effective Java 3rd.Edition 翻譯

    摘要:推薦序前言致謝第一章引言第二章創(chuàng)建和銷毀對(duì)象第項(xiàng)用靜態(tài)工廠方法代替構(gòu)造器第項(xiàng)遇到多個(gè)構(gòu)造器參數(shù)時(shí)要考慮使用構(gòu)建器第項(xiàng)用私有構(gòu)造器或者枚舉類型強(qiáng)化屬性第項(xiàng)通過私有構(gòu)造器強(qiáng)化不可實(shí)例化的能力第項(xiàng)優(yōu)先考慮依賴注入來引用資源第項(xiàng)避免創(chuàng)建不必要的對(duì)象 推薦序 前言 致謝 第一章 引言 第二章 創(chuàng)建和銷毀對(duì)象 第1項(xiàng):用靜態(tài)工廠方法代替構(gòu)造器 第2項(xiàng):遇到多個(gè)構(gòu)造器參數(shù)時(shí)要考慮使用構(gòu)建器 第...

    KoreyLee 評(píng)論0 收藏0
  • Effective Java 第三版 全文翻譯

    摘要:本章中的大部分內(nèi)容適用于構(gòu)造函數(shù)和方法。第項(xiàng)其他方法優(yōu)先于序列化第項(xiàng)謹(jǐn)慎地實(shí)現(xiàn)接口第項(xiàng)考慮使用自定義的序列化形式第項(xiàng)保護(hù)性地編寫方法第項(xiàng)對(duì)于實(shí)例控制,枚舉類型優(yōu)先于第項(xiàng)考慮用序列化代理代替序列化實(shí)例附錄與第版中項(xiàng)目的對(duì)應(yīng)關(guān)系參考文獻(xiàn) effective-java-third-edition 介紹 Effective Java 第三版全文翻譯,純屬個(gè)人業(yè)余翻譯,不合理的地方,望指正,感激...

    galois 評(píng)論0 收藏0
  • 《java 8 實(shí)戰(zhàn)》讀書筆記 -第三章 Lambda表達(dá)式

    摘要:利用前面所述的方法,這個(gè)例子可以用方法引用改寫成下面的樣子構(gòu)造函數(shù)引用對(duì)于一個(gè)現(xiàn)有構(gòu)造函數(shù),你可以利用它的名稱和關(guān)鍵字來創(chuàng)建它的一個(gè)引用。 第三章 Lambda表達(dá)式 函數(shù)式接口 函數(shù)式接口就是只定義一個(gè)抽象方法的接口,哪怕有很多默認(rèn)方法,只要接口只定義了一個(gè)抽象方法,它就仍然是一個(gè)函數(shù)式接口。 常用函數(shù)式接口 showImg(https://segmentfault.com/img...

    whinc 評(píng)論0 收藏0

發(fā)表評(píng)論

0條評(píng)論

最新活動(dòng)
閱讀需要支付1元查看
<