Lambda
匿名內部類已經是一種簡潔的表示方法了,但是還有一個問題,例如一個接口,它只含有一個方法,那麼匿名內部類就不那麼易於使用了,因爲會出現很多冗餘的代碼,這個時候開發者就會想要將函數當成一個參數傳遞給一個方法,例如爲控件設置點擊事件。所以就出現了Lambda表達式,Java8引入了這個新特性,使用Android Studio編程時,會發現爲控件設置點擊事件的代碼會“變樣”,如下第二種表示方式就是Lambda表達式,既然官方都這樣用了,那我們還有什麼理由不擁抱這種方式呢。
view.setOnClickListener(new View.OnClickListener() {//明明是這樣寫的
@Override
public void onClick(View v) {
}
});
view.setOnClickListener((v) -> {//有的時候代碼看上去變成了這樣
});
用法
-
android { buildToolsVersion "24.0.0"//大於24即可 defaultConfig { jackOptions { enabled true } } compileOptions { sourceCompatibility JavaVersion.VERSION_1_8 targetCompatibility JavaVersion.VERSION_1_8 } }
語法
- Lambda表達式只適用於只含有一個方法的接口
- Lambda表達式的結構:(Type params) -> {block},整個表達式代表的是“接口的實現類”;params代表這個“接口中的方法的形參”;Type代表“形參的類型”,可以省略;block代表“接口中方法的實現“,具體請看下面的例子;
public interface ISyntax {//Lambda表達式只適用於只含有一個方法的接口 int getInt(int i); } private void invokeSyntax(ISyntax s) {//調用這個方法需要傳遞ISyntax的實現類 s.getInt(10); } private void learnSyntax() { //匿名內部類已經省略了聲明對象這個步驟,看起來很簡潔了。 invokeSyntax(new ISyntax() { @Override public int getInt(int i) { return i++; } }); // Lambda表達式其實也是匿名的,只不過不僅僅匿了對象名稱,還匿了類名,方法名 invokeSyntax((int i) -> { //這裏的int i就是接口ISyntax中的getInt()方法中的參數 return i++; //大括號中的內容就是getInt()方法的實現 }); invokeSyntax((i) -> i++);//可以省略參數類型,還可以省略大括號和“return”,直接寫返回值 }
- 作用域
import java.util.function.Consumer; public class LambdaScopeTest { public int x = 0; class FirstLevel { public int x = 1; void methodInFirstLevel(int x) { // The following statement causes the compiler to generate // the error "local variables referenced from a lambda expression // must be final or effectively final" in statement A: // // x = 99; Consumer<Integer> myConsumer = (y) -> { System.out.println("x = " + x); // Statement A System.out.println("y = " + y); System.out.println("this.x = " + this.x); System.out.println("LambdaScopeTest.this.x = " + LambdaScopeTest.this.x); }; myConsumer.accept(x); } } public static void main(String... args) { LambdaScopeTest st = new LambdaScopeTest(); LambdaScopeTest.FirstLevel fl = st.new FirstLevel(); fl.methodInFirstLevel(23); } } This example generates the following output: x = 23 y = 23 this.x = 1 LambdaScopeTest.this.x = 0
返回類型
Lambda表達式只含有形參列表和實現代碼塊,那麼Java如何判斷一個Lambda表達式代表的究竟是哪個接口的實現類呢?看下面的例子:
//Target Type public interface IInteger { void setInt(int i); } public interface IString { void setString(String str); } public interface IMultiParams { void setString(String str1, String str2); } public interface IReturn { String getString(String str); } private void use(IInteger e) { e.setInt(1); } private void use(IString t) { t.setString("IString"); } private void use(IMultiParams m) { m.setString("param1", "param2"); } private void use(IReturn r) { r.getString("IReturn"); } public void learnTargetType() { //IInteger use((int i) -> {//該Lambda代表的是IInteger的實現類,因爲參數聲明瞭爲int類型 Log.d(TAG, "i: " + i); }); //IString use((String str) -> { Log.d(TAG, "str: " + str); }); //IMultiParams use((param1, param2) -> { Log.d(TAG, "param1: " + param1 + " param2: " + param2); }); //IReturn use((String str) -> "我有返回值" + str); }
官網總結了以下幾點判斷Target Type(目標類型)的方法
Variable declarations 變量聲明
Assignments
Return statements 返回值聲明
Array initializers 數組初始化
Method or constructor arguments 方法或構造函數參數
Lambda expression bodies Lambda表達式代碼塊
Conditional expressions, ?: 條件表達式
Cast expressions
優點
- Lambda表達式其實就是匿名函數,簡潔,去除了沒有實際意義的代碼;
- 缺點
- 這個也不算是缺點,使用Lambda表達式必須要對函數非常的熟悉,知道它含有什麼參數;
-
參考文章:Oracle官網、Android開發者網站。