天天看點

lambda方法引用總結——燒腦吃透

lambda是java8的新特性,基本使用比較容易了解,但有一個環節遇到了坎兒,那就是方法引用,尤其是類的執行個體方法引用,燒腦之後總結一下。

在需要函數參數的方法中,我們可以把另一個同類型的方法直接傳入,這稱為方法引用的綁定。類似于C語言中的函數指針。

lambda表達式可以替代方法引用;或者說方法引用是lambda的一種特例,方法引用不可以控制傳遞參數。

需要有無參的構造器。

so easy,隻要靜态方法的參數清單和FI需要的參數一緻就可以。

so easy,隻要成員方法的參數清單和FI需要的參數一緻就可以。

��,前方高能,請關掉耳機的音樂,認真思考,小心行事。

傳統的java開發中,是不允許使用類名去調用成員方法的,這是一個基本原則,那麼這裡的這種寫法就有點不太容易了解了。還是用執行個體說明:

用到的内部類:

測試代碼:

小結一下:

前面的例子,FI的兩個參數是同一個類型,如果類型不同呢?省略了哪個參數呢?

是按照位置省略了第一個,亦或者是省略了最後一個?

還是按照類型自動去對應,而不關心第幾個呢?

這個時候,我們能想到的辦法可能是去看源碼,但是一般看代碼沒有個把禮拜甚至更長,毛都看不出來。我們還是用一個例子來分析一下吧。

定義一個FI接口:

編寫兩個用于參數的類:

TestBean1.java

TestBean2.java

二者差別不大。

編寫測試類:

測試方法中,除了标記OK的行正确,其他都報錯。

分析:

首先我們要明确FI需要的參數清單是:(TestBean1,TestBean2)

我們先看①行,我們傳入的”::”前導的類是TestBean1,而expect1方法比對的是TestBean1類型的入參bean1,也就是說省略了TestBean2類型的參數bean2,FI中的最後一個參數。即便我們使用類TestBean1去new一個對象,也找不到TestBean2,是以這個錯誤。

我們先看②行,我們傳入的”::”前導的類是TestBean1,而expect2方法比對的是TestBean2類型的入參bean2,也就是說省略了TestBean1類型的參數bean1,那麼lambda就可以使用”::”前導的TestBean1建構一個對象,作為第一個參數,進而比對FI的接口方法。ok。

我們先看③行,我們傳入的”::”前導的類是TestBean2,而expect1方法比對的是TestBean1類型的入參bean1,也就是說省略了TestBean2類型的參數bean2,FI的最後一個參數。按照第二步的分析,我們用”::”前導的類TestBean2去new一個對象,應該可以湊足兩個參數。實際測試會發現這不靈。這就證明了隻能省略第一個參數,而且,用”::”前導的類也必須是第一個參數的類型。

同第一步類似,第④行代碼,找不到TestBean1的參數,有錯誤可以了解。

至于⑤~⑧,隻是替換了外層的test1的主體,沒有任何差別。這證明了,lambda的比對與外層是什麼鬼沒有任何關系,它隻關心外層需要的FI的參數清單。

請不要看下一步,在這裡停下來冷靜的思考一下,如果我們把TestInterface中FI方法的參數位置換一下,即<code>public void anyStringAsName(TestBean2 cat,TestBean1 dog);</code>,結果應該是哪兩行正确呢?認真思考一下,實在想不明白跑一下測試用例,也許對了解更有幫助。

如果想明白了用這個思路驗證一下:參照參數清單<code>(TestBean2,TestBean1)</code>,可以确定隻可以省略第一個參數即TestBean2,那麼”::”簽到必須是TestBean2,用于自動建立對象;而未省略的參數是TestBean1,那麼方法名為expect1,結果為<code>xxx(TestBean2::expect1)</code>,即③和⑦,你答對了嗎?