摘要:由此可以看出,使用可以讓你的代碼在某些情況下達到何等的簡潔。如果沒有參數,那么前面的是必須存在的。我們知道中的,而其實就是一個只定義了一個抽象方法的。也就是說,可以訪問定義它的那個方法的局部變量。而在里面,還可以訪問所謂的局部變量。
上次在盆友圈發了一張照片
上面的兩段代碼是完全等效的,但是代碼行數從11行降低到了一行,更不用說在第一段代碼里面,我在run方法的前后以及內部都沒有加入任何的空行。由此可以看出,使用lambda可以讓你的Java代碼在某些情況下達到何等的簡潔。
那么問題來了。。。
Java 8 給我們帶來了lambda,然而在Oracle的文檔中,我沒有找到lambda的定義,wikipedia里面也沒有找到適合Java中的lambda的定義。寫這篇文章的時候,我在這里 看到一篇很好的介紹lambda的文章,它里面給了一個定義,我覺得還挺合適的。
lambda的寫法A lambda expression is a block of code with parameters.
首先列舉一個完整的lambda expression:
(int a, int b) -> { System.out.println("Performing add operation..."); return a+b; }
一個lambda expression由三部分組成:
參數:(int a, int b)是這個lambda expression的參數部分,包括參數類型和參數名
箭頭:->
代碼塊:就是用"{}"包含著的那兩句代碼。
上面說的是一個完整的lambda表達式,在很多情況下,很多東西是可以省略的。比如說,當系統可以根據上下文自動推斷出參數的類型的時候,參數類型是可以省略的。這樣的話就可以寫成:
(a, b) -> { System.out.println("Performing add operation..."); return a+b; }
系統怎么自動推斷出參數類型的呢?這個在下面我們就可以看到。
再比如,如果只有一個參數,而參數的類型又可以自動判斷,那么連()也是可以省略的,那么就寫成了:
a -> { System.out.println("Performing add operation..."); return a+a; }
再再比如,如果代碼塊里面只有一行代碼,那么{}也是可以省略的,那么就寫成了:
a -> return a+a;
是的,可以寫在同一行
a -> return a+a;
讓我們更進一步,在這里,return其實也是沒必要的。
a -> a+a;
Great, 如果沒有參數的話,是不是就可以寫成:
-> a+a
呢?
很可惜,答案是否定的。如果沒有參數,那么前面的()是必須存在的。也就是說,必須寫成:
()-> a+alambda的用法
實際上,如果你直接把上面的代碼放到你的編輯器里面,你的IDE是會報錯的,因為lambda是不能這樣使用的。lambda的使用永遠要跟一個叫做Functional Interface的東西綁定在一起。什么叫Functional Interface呢?Functional Interface也是Java8 中引入的概念.是的,是為了lambda。我們知道java中的interface,而Functional Interface其實就是一個只定義了一個抽象方法的interface。比如Runnable 這個interface就只有一個run方法,那么它就是一個Functional Interface。
如果你對“重復”這件事情比較敏感的話,你可能又有疑問了,什么叫只定義了一個抽象方法的interface?interface中的方法不都是抽象的嗎?你這個是病句吧,重復了。。。Well,在java8以前是這樣的,然而在java8中,Java引進了default method的概念,說白了就是帶有具體實現的方法:
public interface DuckInterface { public void wwwalksLikeADuck(); public default void tttalksLikeADuck() { System.out.println("Quack!"); } }
在上面的例子中,tttalksLikeADuck()就是一個default method,注意到這個方法的定義中有一個“default”修飾符。相信很多人會覺得這是個非常有用的feature,我也是這樣覺得的。
再說回Functional Interfacel和lambda。剛剛說到,lambda必須和Functional Interface配套使用,那怎么配套使用呢?
以安卓里面的View.OnClickListener為例(它也是個Functional Interface)如果沒有lambda,我們經常會這樣使用的。
View.OnClickListener onClickListener = new View.OnClickListener() { @Override public void onClick(View view) { handleClick(); } }); findViewById(R.id.someView).setOnClickListener(onClickListener);
或者直接使用匿名內部類:
findViewById(R.id.someView).setOnClickListener(new View.OnClickListener() { @Override public void onClick(View view) { handleClick(); } });
在上面的5行代碼中,有用的其實只有handleClick(),而我們卻必須用5行代碼去處理,這是非常繁瑣的。在Java 8以前的世界,這樣的代碼非常多。有一個專門的名詞來稱呼這種性質的代碼,叫“boilerplate code”,我不知到中文叫什么。。。
現在好了,有了lambda,我們可以這樣寫:
View.OnClickListener onClickListener = view -> handleClick(); findViewById(R.id.someView).setOnClickListener(onClickListener);
匿名內部類的版本:
findViewById(R.id.someView).setOnClickListener(view -> handleClick());
是不是瞬間覺得簡潔優雅了?
從上面的例子可以看到,lambda其實就相當于簡化了Functional Interface的實例的創建。當然,從真正意義上來講,lambda的意義不止這么一點點,只不過從使用的角度來看,你可以這樣看待。
這里稍微討論一下關于lambda的其他一些特性。
在上面的例子中
View.OnClickListener onClickListener = view -> handleClick(); findViewById(R.id.someView).setOnClickListener(onClickListener);
這里,你既可以吧onClickListener看作是OnClickListener的一個instance,也可以把它看做一個代碼塊,后面的那句findViewById(R.id.someView).setOnClickListener(onClickListener);就相當于是吧這個代碼塊傳給了view.setOnClickListener()這個函數。也就是說,從某種意義上來講,你可以把lambda看作是可以相互傳遞的代碼塊。而傳遞代碼塊,是Functional Programming(一下簡稱FP)非常重要的一個特征,雖然說這兩者其實沒有什么對等關系。因為FP的本質特征是,運行一段代碼并不會改變事物的狀態,也就是說,沒有side-effect。而lambda里面是可以調用所在的類的成員方法的、也可以訪問和修改所在類的成員變量的。
話說回來,關于FP我也不是了解的很多,我本身并沒有多少FP的經驗,雖然對Ruby有一定了解,但Ruby也只是“可以比較好的進行”FP而已,也不是純粹的FP語言。純粹的FP語言是List(包括Scheme,Clojure)、Haskell、ML等等這些。關于FP,Robert Martin(就是《Clean code》和《The Clean Coder》的作者)有一個講得很好的視頻在這里。
剛剛講到,lambda的代碼塊可以訪問所在類的成員變量和成員方法,那對于局部變量?
我們知道,方法內部定義的匿名類是可以訪問所在方法的final局部變量的,作為Functional Interface的簡寫方式,lambda在這點上面跟匿名類保持了一致。也就是說,lambda可以訪問定義它的那個方法的final局部變量。而在Java8里面,lambda還可以訪問所謂“Effectively final”的局部變量。所謂“Effectively final”的局部變量,就是說除了在定義的時候給了一個初始值以為,在沒有改變過她的值的那些局部變量:
int age = 26; //在這里,age就是Effectively final的局部變量 Runnable r = () -> System.out.println("My age is "+age); new Thread(r).start();在Android開發中的應用
可是!!!Android只支持Java 7啊?怎么辦?莫急,要相信網友的力量,已經有人開發了gradle的插件,可以將java 8中的labmda表達式在編譯出來的bytecode里面,給它轉化成Java 7兼容的代碼。猛戳這里,使用方法那個頁面都用,在這里就不贅述了。
如果對文章有任何意見或建議,或者是發現文中有任何問題歡迎留言!
作者 小創 更多文章 | Github | 公眾號
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/64358.html
摘要:可能是最流行的集合類型。它是一個范性有序的集合。一個無序并不支持重復的集合。接口繼承接口,集合中可以存放重復對象。集合類提供了,等高階函數去處理。我們聲明一個集合或者數組,可以轉換成相應類型的集合。調用轉換為可變集合。 不積跬步無以至千里,不積小流無以成江海 先看看Kotlin中for循環的遍歷 fun testList(){ var StringVal = 12_...
摘要:現在爸爸終于讓平臺支持了,這篇文章中便來和大家聊聊如何在項目中配置使用。要想在項目中使用的新特性,需要將你的升級到及以上版本,并采用新的編譯。 轉載請注明出處:https://zhuanlan.zhihu.com/p/23279894 前言 在過去的文章中我介紹過Java8的一些新特性,包括: Java8新特性第1章(Lambda表達式) Java8新特性第2章(接口默認方法) J...
閱讀 1617·2019-08-29 13:53
閱讀 3215·2019-08-29 13:50
閱讀 860·2019-08-27 10:51
閱讀 571·2019-08-26 18:36
閱讀 1811·2019-08-26 11:00
閱讀 610·2019-08-26 10:36
閱讀 3222·2019-08-23 17:58
閱讀 2037·2019-08-23 15:17