| Markdown版本筆記 | 我的GitHub首頁 | 我的博客 | 我的微信 | 我的郵箱 |
|---|---|---|---|---|
| MyAndroidBlogs | baiqiantao | baiqiantao | bqt20094 | baiqiantao@sina.com |
目錄
Lambda 表達式
Lambda 表達式也稱為閉包,是匿名內部類的簡短形式。
Lambda 表達式簡化了單一方法聲明接口的使用,因此 lambda 表達式也稱為功能接口(只有一個抽象方法的接口)。
使用 lambda 表達式實現功能接口時,無需創建類或匿名類。
Lambda 表達式具有以下優點:
- 簡明的語法
- 方法引用和構造函數引用
- 相比於匿名類,減少了運行時開銷
基本語法
(formal parameter list) -> {
expression or statements
}
參數列表
- 參數列表是一個逗號分隔的
形式參數列表,這些參數與功能接口中單一方法的形式參數相對應。 - 參數列表中的
參數類型是可選項,如果未指定參數類型,將從上下文推斷。 - 參數列表必須用
小括號括起來,但如果只有一個參數且不帶參數類型時小括號可以省略。 - 參數列表如果為空(即:功能接口方法沒有形式參數),則必須指定
空括號。
Lambda 主體根據以下選項之一返回結果:
- 如果 lambda 主體是單一表達式,則返回表達式的值(如果有的話)。
- 如果功能接口方法的結果是 void,可以提供一個 return 語句,但這不是必需的。
- 如果功能接口方法具有返回類型,且 lambda 主體不是單一表達式,則 lambda 主體必須使用 return 語句返回匹配的值。
語句塊必須包含在大括號內,除非語句塊是一個方法調用語句,且功能接口方法的返回結果是void。
Lambda 表達式實際上是一種匿名方法實現,指定形式參數,並使用 return 語句返回值。匿名方法必須按照以下規則所規定的與其實現的功能接口方法兼容。
- Lambda 表達式返回的結果必須與功能接口方法的結果兼容。返回值的類型可以是功能接口方法聲明中返回類型的子類型。
- Lambda 表達式簽名必須與功能接口方法的簽名相同。
- Lambda 表達式只能拋出那些在功能接口方法的 throws 子句中聲明了異常類型或異常超類型的異常。
Lambda 表達式中的局部變量
Lambda 表達式不會定義新的作用域,lambda 表達式的作用域與封閉作用域相同。
Lambda 主體中的 this 和 super 引用與封閉上下文中一樣,因為 lambda 表達式不會引入新的作用域,這與匿名類不同。
如果 Lambda 主體聲明的局部變量與封閉作用域內的變量重名,將產生編譯器錯誤
Lambda expression's local variable i cannot re-declare another local variable defined in an enclosing scope
局部變量無論是在 lambda 表達式主體中聲明,還是在封閉作用域中聲明,使用之前都必須先初始化,否則將產生編譯器錯誤
The local variable i may not have been initialized
lambda 表達式中使用的變量必須處於終態或等效終態,否則將產生編譯器錯誤
Variable i is required to be final or effectively final
啟用 Lambda 表達式
在AS中使用 Lambda 表達式
File -> Project Structure -> SDK location -> JDK location -> JDK版本選擇1.8
android {
compileOptions {
targetCompatibility JavaVersion.VERSION_1_8
sourceCompatibility JavaVersion.VERSION_1_8
}
}
在Eclipse中使用 Lambda 表達式
前提條件
- 1、安裝了 JDK 8 的 JRE
- 2、
所使用的 Eclipse 要支持 Java8 的編譯
步驟
- 在 Eclipse 中,選擇 Windows > Preferences > Java >
Installed JREs,勾選JDK 8 的 JRE - 選擇 Windows > Preferences > Java > Compiler,然后將
Compiler compliance level設為 1.8。如果沒有 1.8 的選項,說明此eclipse版本不支持。 - 單擊 Apply,然后單擊 OK。
Eclipse Luna SR2已經添加了對Java8的支持,可直接到官網下載
使用示例
沒有參數
new Thread(() -> {
System.out.println("包青天");
}).start();
只有一行語句時,可以進一步簡化為:
new Thread(() -> System.out.println("包青天")).start();
new Thread(() -> runOnUiThread(() -> System.out.println("包青天"))).start();
但是如果有多行語句,就沒法簡化了
單一參數
imageView.setOnClickListener(v -> {
Toast.makeText(this, "包青天", Toast.LENGTH_SHORT).show();
});
同樣,只有一行語句時,可以進一步簡化為:
imageView.setOnClickListener((View v) -> System.out.println("包青天")); //帶類型
imageView.setOnClickListener((v) -> System.out.println("包青天")); //帶小括號
imageView.setOnClickListener(v -> System.out.println("包青天")); //省略小括號
imageView.setOnClickListener(v -> System.out.println(v));
如果只有一行方法引用的語句,且此方法沒有返回值,且此方法僅有一個參數,且此方法的此參數就是 Lambda 表達式中參數列表中的那個參數,可以進一步簡化為方法引用(method reference):
imageView.setOnClickListener(v -> test(v));
imageView.setOnClickListener(this::test); //普通方法
imageView.setOnClickListener(System.out::println); //靜態方法
imageView.setOnClickListener(SplashActivity::test); //靜態方法
多個參數
listView.setOnItemClickListener((AdapterView<?> parent, View view, int position, long id) -> {
Toast.makeText(this, "position=" + position, Toast.LENGTH_SHORT).show();
});
同樣,只有一行語句時,可以進一步簡化為:
listView.setOnItemClickListener((AdapterView<?> parent, View view, int position, long id) -> System.out.println(position));
listView.setOnItemClickListener((parent, view, position, id) -> System.out.println(position));
使用局限性
1、只適用於單一方法的接口,如果接口有多個需要實現的方法,則不能使用,如:
listView.setOnScrollListener(new AbsListView.OnScrollListener() {
@Override
public void onScrollStateChanged(AbsListView view, int scrollState) {
}
@Override
public void onScroll(AbsListView view, int first, int count, int total) {
}
});
這是 Lambda 表達式最大的局限性
2、如果需要在匿名內部類中定義成員變量,則不能使用,如:
listView.setOnClickListener(new View.OnClickListener() {
private boolean b;
@Override
public void onClick(View v) {
}
});
其實這里的成員變量沒有任何意義,和定義成局部變量沒什么區別
3、如果需要在匿名內部類中使用到匿名內部類的this、super,而非如外部類的this、super,則不能使用,如:
view.getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
@Override
public void onGlobalLayout() {
//這里的this代表的是匿名內部類OnGlobalLayoutListener
view.getViewTreeObserver().removeOnGlobalLayoutListener(this);//使用到了this
}
});
Lambda 主體中的 this、super 引用與封閉上下文中一樣,因為 lambda 表達式不會引入新的作用域,這與匿名類不同。
Lambda 表達式中使用的this、super是指外部類,其實往往這是 Lambda 的優點而非缺點,因為我們往往需要的就是外部類的this、super
2017-07-17
