實(shí)例講解Java8新特性——方法引用

?前幾天同事跑過來說有行代碼看不懂窥翩,問我懂不懂。代碼是android 8.0原生代碼氓仲,路徑是frameworks/base/packages/SystemUI/src/com/android/systemui/statusbar/phone/DarkIconDispatcherImpl.java水慨,
代碼如下:

44        mTransitionsController = new LightBarTransitionsController(context,
45                this::setIconTintInternal);

public LightBarTransitionsController(Context context, DarkIntensityApplier applier) 

?this::setIconTintInternal是什么鬼?沒見過熬纯浮晰洒!LightBarTransitionsController的構(gòu)造方法需要傳一個(gè)DarkIntensityApplier類,但是實(shí)參卻是this::setIconTintInternal啥箭,看著像是一個(gè)方法谍珊。再看DarkIntensityApplier的定義,它其實(shí)是一個(gè)接口:

202    public interface DarkIntensityApplier {
203        void applyDarkIntensity(float darkIntensity);
204    }

?通過搜索發(fā)現(xiàn)this::setIconTintInternal的用法叫方法引用急侥,是java 8的新特性砌滞。下面我們就來探究一下它的用法和原理。在開始之前坏怪,我們先列一下對(duì)上面代碼的疑問:

  1. 為什么this::setIconTintInternal可以被轉(zhuǎn)換成一個(gè)接口贝润?
  2. setIconTintInternal 跟 DarkIntensityApplier接口是什么關(guān)系?
  3. setIconTintInternal 什么時(shí)候會(huì)被調(diào)用铝宵?

方法引用入門

?方法引用和lambda表達(dá)式一樣打掘,都是java 8為了增強(qiáng)java語言表現(xiàn)力而引入的华畏。我們舉最常用的click listener這個(gè)例子看一下它們的用法。
?java 8之前我們的寫法是這樣的:

 View.OnClickListener listener = new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                Log.d(TAG, "click");
            }
        };
 button.setOnClickListener(listener);

?使用lambda表達(dá)式的寫法是這樣的:

button.setOnClickListener(v -> Log.d(TAG, "click"));

?lambda表達(dá)式的形式是尊蚁, 參數(shù) -> 執(zhí)行語句; 如果有多個(gè)參數(shù)和多條執(zhí)行語句時(shí)可以這樣寫: (參數(shù)1, 參數(shù)2) -> {執(zhí)行語句; 執(zhí)行語句2;}

?使用方法引用的寫法是這樣的:

button.setOnClickListener(this::onButtonClick);
private void onButtonlick(View v) {
    Log.d(TAG, "click");
}

?我們發(fā)現(xiàn)lambda表達(dá)式最簡(jiǎn)練亡笑,方法引用次之。而方法引用有一個(gè)lambda表達(dá)式做不到的地方横朋,就是把實(shí)現(xiàn)和調(diào)用分離÷匚冢現(xiàn)在我們就可以回答第一個(gè)問題了,為什么this::setIconTintInternal可以被轉(zhuǎn)換成一個(gè)接口琴锭?因?yàn)閠his::setIconTintInternal是一個(gè)方法引用晰甚,在編譯階段,就會(huì)把它編譯成對(duì)應(yīng)的接口决帖。當(dāng)然編譯通過有以下條件:

  1. 這個(gè)接口只有一個(gè)抽象方法压汪;也就是這個(gè)接口是一個(gè)函數(shù)式接口(FunctionalInterface);
  2. 被引用的方法參數(shù)必須和接口的抽象方法的參數(shù)一致古瓤,方法名和返回類型不要求一致;
    如果方法參數(shù)不一致會(huì)報(bào)下面的編譯錯(cuò)誤:
error: incompatible types: invalid method reference
incompatible types: View cannot be converted to int

?我們可以使用類靜態(tài)方法腺阳、對(duì)象的實(shí)例方法落君、構(gòu)造方法作為方法引用;引用構(gòu)造方法的寫法比較特殊亭引,形式如下绎速,ClassName::new。

一行代碼實(shí)現(xiàn)列表排序

?從上面的介紹中我們知道lambda表達(dá)式和方法引用只適用于函數(shù)式接口焙蚓,除了上面的 Click listener纹冤,還有哪些常用的函數(shù)式接口呢?用于排序的Comparator是一個(gè)购公。下面我們來看如何使用方法引用用一行代碼實(shí)現(xiàn)列表排序萌京。我們定義一個(gè)Person類,根據(jù)age進(jìn)行排序宏浩。

public class Person {
    private int age;
    public int getAge() {return age;}
    public void setAge(int age) {this.age = age;}
}
List<Person> personList = new ArrayList<>();
personList.add(...);

?在java 8之前知残,我們會(huì)定義一個(gè)Comparator,在compare方法里實(shí)現(xiàn)排序條件:

    class MyComparator implements Comparator<Person>{

        @Override
        public int compare(Person o1, Person o2) {
            return o1.age - o2.age;
        }
    }
    Collections.sort(personList, new MyComparator());

?使用lambda表達(dá)式比庄,我們可以不定義MyComparator求妹,

Collections.sort(personList, (p1, p2) -> p1.age - p2.age);

?使用方法引用如何實(shí)現(xiàn)呢?

Collections.sort(personList, comparing(Person::getAge()));

?這里借助了Comparator 里的 comparing 方法實(shí)現(xiàn)比較操作佳窑,不再需要人工做比較制恍。另外,利用List接口里的sort方法神凑,可以做到更簡(jiǎn)化:

 personList.sort(comparing(Person::getAge));

?如果我們?yōu)?Comparator 接口增加一個(gè)默認(rèn)方法 reversed()(產(chǎn)生一個(gè)逆序比較器)净神,我們就可以非常容易的在前面代碼的基礎(chǔ)上實(shí)現(xiàn)降序排序。

people.sort(comparing(Person::getAge).reversed());

總結(jié)

?上面我們通過列表排序的例子,使用lambda表達(dá)式和方法引極大的簡(jiǎn)化了代碼强挫。也基本解決了文章開始的疑問岔霸。但是很難說做到了融會(huì)貫通、舉一反三俯渤。后面將繼續(xù)探究java對(duì)函數(shù)式接口的支持呆细。敬請(qǐng)期待~

參考

深入理解Java 8 Lambda(語言篇——lambda,方法引用八匠,目標(biāo)類型和默認(rèn)方法)
30分鐘入門Java8之lambda表達(dá)式
30分鐘入門Java8之方法引用

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末絮爷,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子梨树,更是在濱河造成了極大的恐慌坑夯,老刑警劉巖,帶你破解...
    沈念sama閱讀 218,546評(píng)論 6 507
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件抡四,死亡現(xiàn)場(chǎng)離奇詭異柜蜈,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)指巡,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,224評(píng)論 3 395
  • 文/潘曉璐 我一進(jìn)店門淑履,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人藻雪,你說我怎么就攤上這事秘噪。” “怎么了勉耀?”我有些...
    開封第一講書人閱讀 164,911評(píng)論 0 354
  • 文/不壞的土叔 我叫張陵指煎,是天一觀的道長(zhǎng)。 經(jīng)常有香客問我便斥,道長(zhǎng)至壤,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,737評(píng)論 1 294
  • 正文 為了忘掉前任枢纠,我火速辦了婚禮崇渗,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘京郑。我一直安慰自己宅广,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,753評(píng)論 6 392
  • 文/花漫 我一把揭開白布些举。 她就那樣靜靜地躺著跟狱,像睡著了一般。 火紅的嫁衣襯著肌膚如雪户魏。 梳的紋絲不亂的頭發(fā)上驶臊,一...
    開封第一講書人閱讀 51,598評(píng)論 1 305
  • 那天挪挤,我揣著相機(jī)與錄音,去河邊找鬼关翎。 笑死扛门,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的纵寝。 我是一名探鬼主播论寨,決...
    沈念sama閱讀 40,338評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼,長(zhǎng)吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼爽茴!你這毒婦竟也來了葬凳?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 39,249評(píng)論 0 276
  • 序言:老撾萬榮一對(duì)情侶失蹤室奏,失蹤者是張志新(化名)和其女友劉穎火焰,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體胧沫,經(jīng)...
    沈念sama閱讀 45,696評(píng)論 1 314
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡昌简,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,888評(píng)論 3 336
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了绒怨。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片江场。...
    茶點(diǎn)故事閱讀 40,013評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖窖逗,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情餐蔬,我是刑警寧澤碎紊,帶...
    沈念sama閱讀 35,731評(píng)論 5 346
  • 正文 年R本政府宣布,位于F島的核電站樊诺,受9級(jí)特大地震影響仗考,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜词爬,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,348評(píng)論 3 330
  • 文/蒙蒙 一秃嗜、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧顿膨,春花似錦锅锨、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,929評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至囊咏,卻和暖如春恕洲,著一層夾襖步出監(jiān)牢的瞬間塔橡,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,048評(píng)論 1 270
  • 我被黑心中介騙來泰國打工霜第, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留葛家,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 48,203評(píng)論 3 370
  • 正文 我出身青樓泌类,卻偏偏與公主長(zhǎng)得像癞谒,于是被迫代替她去往敵國和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子末誓,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,960評(píng)論 2 355

推薦閱讀更多精彩內(nèi)容