ITEM 43: PREFER METHOD REFERENCES TO LAMBDAS
??lambdas相對于匿名類的主要優(yōu)勢是它們更簡潔。Java提供了一種生成函數(shù)對象的方法妹笆,甚至比lambdas 更簡潔块请,這就是方法引用。下面是一個程序的代碼片段晾浴,該程序維護從任意鍵到整數(shù)值的映射。如果該值被解釋為鍵的實例數(shù)的計數(shù)牍白,則該程序是一個多集實現(xiàn)脊凰。代碼段的作用是:如果鍵不在映射中,則將數(shù)字1與鍵關(guān)聯(lián)茂腥;如果鍵已經(jīng)存在狸涌,則增加關(guān)聯(lián)的值:
map.merge(key, 1, (count, incr) -> count + incr);
??注意,這段代碼使用了merge方法最岗,該方法是在Java 8中添加到 Map 接口中的帕胆。如果給定鍵沒有映射,則該方法只是插入給定的值般渡;如果已經(jīng)存在映射懒豹,merge將給定的函數(shù)應用于當前值和給定的值,并使用結(jié)果覆蓋當前值驯用。這段代碼代表了合并方法的一個典型用例脸秽。代碼讀起來很好,但是仍然有一些樣板文件蝴乔。參數(shù)計數(shù)和incr沒有增加多少值记餐,并且它們占用了相當多的空間。實際上薇正,告訴你的只是函數(shù)返回它的兩個參數(shù)的和片酝。從Java 8開始囚衔,Integer(以及所有其他裝箱的數(shù)值原語類型)提供了一個靜態(tài)方法 sum,它做的是完全相同的事情雕沿。我們可以簡單地傳遞一個引用到這個方法练湿,并得到相同的結(jié)果與較少的視覺混亂:
map.merge(key, 1, Integer::sum);
??方法擁有的參數(shù)越多,您可以通過方法引用消除的樣板文件就越多晦炊。但是鞠鲜,在某些lambdas中,您選擇的參數(shù)名提供了有用的文檔断国,使得 lambda 比方法引用更具可讀性和可維護性贤姆,即使lambda更長。
??你不能對一個方法引用做任何你不能對 lambda 做的事情(除了一個模糊的例外——如果你好奇的話稳衬,可以看看JLS, 9.9-2)霞捡。也就是說,方法引用通常會產(chǎn)生更短薄疚、更清晰的代碼碧信。如果一個lambda 變得太長或太復雜,也許你應該這么做:你可以從lambda中提取代碼到一個新方法中街夭,并用對該方法的引用替換lambda砰碴。您可以為該方法起一個好名字,并將其文檔化為您的核心內(nèi)容板丽。
??如果您使用IDE進行編程呈枉,它將在任何可能的地方用方法引用替換 lambda。大多數(shù)情況下你應該接受 IDE 的提議埃碱。有時候猖辫,lambda 會比方法引用更簡潔。這種情況最常發(fā)生在方法與 lambda 在同一個類中砚殿。例如啃憎,考慮這個代碼片段,它被假定發(fā)生在一個名為GoshThisClassNameIsHumongous 的類中:
service.execute(GoshThisClassNameIsHumongous::action);
??用 lambda 實現(xiàn)看起來是這樣的:
service.execute(() -> action());
??使用方法引用的代碼段與使用 lambda 的代碼段相比既不短也不清楚似炎,因此最好使用后者辛萍。與此類似,F(xiàn)unction 接口提供了一個通用的靜態(tài)工廠方法來返回 identity 函數(shù) Function.identity()羡藐。它通常更短叹阔,更簡潔,不使用這個方法传睹,但代碼等價的 lambda 內(nèi)聯(lián): x -> x耳幢。
??許多方法引用是靜態(tài)方法,但是有四種方法不是靜態(tài)方法。其中兩個是綁定的和未綁定的實例方法引用睛藻。在綁定引用中启上,接收對象在方法引用中指定。綁定引用在本質(zhì)上與靜態(tài)引用相似:函數(shù)對象采用與引用方法相同的參數(shù)店印。在未綁定引用中冈在,在應用函數(shù)對象時,通過方法聲明參數(shù)之前的附加參數(shù)指定接收對象按摘。未綁定的引用通常用作流管道中的映射和篩選函數(shù)(item 45)包券。最后,類和數(shù)組有兩種構(gòu)造函數(shù)引用炫贤。構(gòu)造函數(shù)引用作為工廠對象溅固。5類方法參考文獻匯總?cè)缦卤?
??總之,方法引用常常提供比 lambdas 更簡潔的替代方法兰珍。如果方法引用更短侍郭、更清晰,請使用它們掠河;如果沒有亮元,就用lambdas。