Java8 開發的 4 大頂級技巧

正文

我使用 Java 8 編碼已經有些年頭,既用於新的應用程序,也用來遷移現有的應用,感覺是時候寫一些我發現的非常有用的 “最佳實踐”。

我個人並不喜歡 “最佳實踐” 這個說法,因爲它意味着 “一刀切” 的解決方案,而編碼不可能是這樣的工作方式——我們需要親自去發現什麼樣的解決方案纔是有效的。但是我發現了一些 Java 8 代碼中可以幫助我們的一些選擇,讓我們一起來看看吧。

1.Optional

Optional 是一個嚴重被低估的功能,並且有潛力刪除很多困擾我們的 NullPointerExceptions。這在代碼邊界中(要麼是正在使用的 API,要麼是正在暴露的 API)特別有用,因爲它允許你和你的調用代碼來推理所期待的東西。

然而,不加思考和設計就應用 Optional 可能會導致影響大量的類,並可能導致可讀性更差。下面是一些關於如何高效使用 Optional 的技巧。

Optional 應該只用於返回類型

…… 不是參數,也不是字段。幸運的是,IntelliJ IDEA 的讓你打開檢查來查看是是否遵循這些建議。

Optional 值應在遇到它們的地方中處理。IntelliJ IDEA 的建議會防止代碼 Optional 泄漏,所以請記得在你發現 Optional 的地方處理它,迅速採取行動。

不應該簡單調用 get()

Optional 的功能是表達這個值可能是空的,並讓你應對這種情況。因此,在對它做任何事情之前一定要檢查是否有一個值。只是簡單得調用 get() 而不先檢查 isPresent() 在某些時候可能會導致空指針。幸運的是,IntelliJ IDEA 也有檢查可以提醒你這一點。

可能有更優雅的方式

結合了 get() 的 isPresent() 當然會很贊…

…… 但也有更優雅的解決方案。你可以使用 orElse 在萬一是空值的情況下給一個替代方案。

…… 或者你可以使用 orElseGet 說明在值爲空的情況下調用哪個方法。這似乎與上面的例子相同,但 supplier 方法將只在需要的時候調用,因此,如果這是一種昂貴的方法,那麼使用 lambda 會有更佳性能。

  1. 使用 Lambda 表達式

Lambda 表達式是 Java 8 的主要特點之一。即使你還沒有使用 Java 8,你現在可能已經對它們有了基本的瞭解。它們是用 Java 編程的一種新的方式,並且什麼是 “最佳實踐” 還不明顯。下面是我喜歡遵循的一些指引。

保持簡短

函數式程序員與較長的 lambda 表達式相處會更愉快,但那些淫浸於 Java 多年的人會發現保持 lambda 表達式爲區區幾行代碼更容易。你甚至可能更願意將其限制到一行代碼,並且你可以輕鬆重構較長的表達式爲一個方法。

這些甚至可能會成爲方法引用。方法引用一開始會覺得有點陌生,但實際上堅持方法引用是有價值的,因爲它們在某些情況下有助於可讀性,後面我會討論到這一點。

明確

類型信息缺少 lambda 表達式,所以你可能會覺得包含類型信息用於參數會很有用。

正如你所見,這回變得相當笨拙。所以我更喜歡給參數取一個有用的名字。當然,不管你有沒有這麼做,IntelliJ IDEA 可以讓你看到參數得類型信息。

甚至是 lambda 所代表的函數式接口:

  1. 針對 Lambda 表達式設計

我認爲 lambda 表達式有點像泛型——和泛型一起,我們經常使用它們(例如,添加類型信息到 List<>),但最好我們可以設計一種方法或一個具有泛型類型(例如 Person< T>)的類。同樣的,當使用類似於 Streams API 的東西時,我們會傳遞 lambda 表達式,但更好的是創造一個需要 lambda 參數的方法。

但是,如果你發現自己處於這類情況下,下面有一些超棒的技巧。

IntelliJ IDEA 可以幫你引進函數式參數

這讓你可以在有人將傳遞一個 lambda 而非 Object 的地方創建一個參數。此功能的好處是,它表明,現有函數式接口匹配規格說明。

這會導致…

使用現有的函數式接口

隨着開發人員越來越熟悉 Java 8 代碼,我們就能知道當使用如 Supplier 和 Consumer 的接口時,會發生什麼,以及創建一個本地的 ErrorMessageCreator(舉個例子)可能會造成混亂,而且浪費。看看這個函數包瞭解一下哪些已經是可用的。

添加 @FunctionalInterface 到函數式接口

如果你確實需要創建自己的函數式接口,那麼就這樣用此註釋標記。這似乎沒有太大的作用,但 IntelliJ IDEA 會告訴你,在你的接口不能匹配用於函數式接口的異常的時候。當你沒有指定要覆蓋的方法時,它會標誌:

當你指定了太多方法的時候,它會標誌:

並且如果你應用它到一個類而不是接口時,它會警告你:

lambda 表達式可用於帶有一個單一抽象方法的任何接口,但它們不能用於符合相同標準的抽象類。似乎不合邏輯,但就是這樣。

4.Stream

Stream API 是 Java 8 另一個大特點,並且我認爲我們還真的不知道這對我們的編碼方式會產生多大的改變。下面是我發現的一些有用的東西

排隊點操作符

我個人更喜歡排隊我的流操作。當然,你沒有必要這樣,當我發現這樣做對我有幫助:

此外,在我看來,它更整潔。如果我們按照這個模式,在減少代碼行數方面我們並沒有增加很多。

你可能需要調整格式設置以排列點操作符。

使用方法引用

是的,確實需要一段時間來適應這個奇怪的語法。但是,如果使用得當,它確實可以增加可讀性。請看:

與(相對)新的 Objects 類上的輔助方法相比較:

後者的代碼對於哪些值是要保存的更加明確。當 lambda 可以被摺疊到方法參考的時候,IntelliJ IDEA 通常會讓你知道。

當遍歷一個集合時,在可行的情況下使用 Streams API

… 或者新的集合方法,如 forEach。IntelliJ IDEA 給你建議是:

一般使用 Streams API 比循環和 if 語句的組合更加明確。例如:

IntelliJ IDEA 建議這可重構爲:

我所做的性能測試表明這種重構令人驚訝——並不總是可預測性能是保持不變,改善還是變得更糟。與往常一樣,如果性能在應用程序中是關鍵,那麼在交付一種風格到另一種之前衡量它。

遍歷數組時使用循環

但是,使用 Java 8 並不一定意味着你必須到處使用流和新的集合方法。IntelliJ IDEA 會建議轉換成流,但是,這並不意味着你必須回答 “yes”(記得檢查是可以抑制或關閉的)。

特別是,遍歷原始類型的小型數組幾乎肯定會用,以獲得更好的性能循環,很可能(至少對於 Java 開發人員是新的流)更具可讀性。

與任何技巧一樣,規則並不是一成不變的,但你應該決定是儘可能地使用 Streams API,還是依然對一些操作使用循環。總之,要一致。

本文由 Readfog 進行 AMP 轉碼,版權歸原作者所有。
來源https://mp.weixin.qq.com/s/PMTKVpYKcNMJHtUlDSyg5g