1. 程式人生 > >Effective Java 第三版——43.方法引用優於lambda表達式

Effective Java 第三版——43.方法引用優於lambda表達式

incr ges ren 常用 eem 占用 pre 我們 his

Tips
《Effective Java, Third Edition》一書英文版已經出版,這本書的第二版想必很多人都讀過,號稱Java四大名著之一,不過第二版2009年出版,到現在已經將近8年的時間,但隨著Java 6,7,8,甚至9的發布,Java語言發生了深刻的變化。
在這裏第一時間翻譯成中文版。供大家學習分享之用。

技術分享圖片

43.方法引用優於lambda表達式

lambda優於匿名類的主要優點是它更簡潔。Java提供了一種生成函數對象的方法,比lambda還要簡潔,那就是:方法引用( method references)。下面是一段程序代碼片段,它維護一個從任意鍵到整數值的映射。如果將該值解釋為鍵的實例個數,則該程序是一個多重集合的實現。該代碼的功能是,根據鍵找到整數值,然後在此基礎上加1:

map.merge(key, 1, (count, incr) -> count + incr);

請註意,此代碼使用merge方法,該方法已添加到Java 8中的Map接口中。如果沒有給定鍵的映射,則該方法只是插入給定值; 如果映射已經存在,則合並給定函數應用於當前值和給定值,並用結果覆蓋當前值。 此代碼表示merge方法的典型用例。

代碼很好讀,但仍然有一些樣板的味道。 參數count和incr不會增加太多價值,並且占用相當大的空間。 真的,所有的lambda都告訴你函數返回兩個參數的和。 從Java 8開始,Integer類(和所有其他包裝數字基本類型)提供了一個靜態方法總和,和它完全相同。 我們可以簡單地傳遞一個對這個方法的引用,並以較少的視覺混亂得到相同的結果:

map.merge(key, 1, Integer::sum);

方法的參數越多,你可以通過方法引用消除更多的樣板。 然而,在一些lambda中,選擇的參數名稱提供了有用的文檔,使得lambda比方法引用更具可讀性和可維護性,即使lambda看起來更長。

對於一個方法引用,你無能為力,因為你不能對lambda執行任何操作(只有一個難懂的異常 - 如果你好奇的話,參見JLS,9.9-2)。 也就是說,方法引用通常會導致更短,更清晰的代碼。 如果lambda變得太長或太復雜,它們也會給你一個結果:你可以從lambda中提取代碼到一個新的方法中,並用對該方法的引用代替lambda。 你可以給這個方法一個好名字,並把它文檔記錄下來。

如果你使用IDE編程,它將提供替換lambda的方法,並在任何地方使用方法引用。通常情況下,你應該接受這個提議。偶爾,lambda會比方法引用更簡潔。這種情況經常發生在方法與lambda相同的類中。例如,考慮這段代碼,它被假定出現在一個名為GoshThisClassNameIsHumongous的類中:

service.execute(GoshThisClassNameIsHumongous::action);

這個lambda類似於等價於下面的代碼:

service.execute(() -> action());

使用方法引用的代碼段既不比使用lambda的代碼片段更短也不清晰,所以更喜歡後者。 在類似的代碼行中,Function接口提供了一個通用的靜態工廠方法來返回標識函數Function.identity()。 它通常更短,更清潔,而不使用這種方法,而是使用等效的lambda內聯代碼:x - > x

許多方法引用是指靜態方法,但有四種方法沒有。 其中兩個是特定(bound)和任意(unbound)對象方法引用。 在特定對象引用中,接收對象在方法引用中指定。 特定對象引用在本質上與靜態引用類似:函數對象與引用的方法具有相同的參數。 在任意對象引用中,接收對象在應用函數對象時通過方法的聲明參數之前的附加參數指定。 任意對象引用通常用作流管道(pipelines)中的映射和過濾方法(條目 45)。 最後,對於類和數組,有兩種構造方法引用。 構造方法引用用作工廠對象。 下表總結了所有五種方法引用:

方法引用類型 舉例 等同的Lambda
Static Integer::parseInt str -> Integer.parseInt(str)
Bound Instant.now()::isAfter Instant then = Instant.now(); t -> then.isAfter(t)
Unbound String::toLowerCase str -> str.toLowerCase()
Class Constructor TreeMap::new () -> new TreeMap
Array Constructor int[]::new len -> new int[len]

總之,方法引用通常為lambda提供一個更簡潔的選擇。 如果方法引用看起來更簡短更清晰,請使用它們;否則,還是堅持lambda

Effective Java 第三版——43.方法引用優於lambda表達式