在AS中使用 Lambda 表达式
Gradle(Project级别)中添加classpath
buildscript {
dependencies {
classpath 'com.android.tools.build:gradle:2.2.2'
classpath 'me.tatarka:gradle-retrolambda:3.2.0'
}
}
Gradle(app级别)中添加apply(第一行)
apply plugin: 'com.android.application'
apply plugin: 'me.tatarka.retrolambda'
Gradle(app级别)的android下添加compileOptions(android标签下)
android {
***
compileOptions {
targetCompatibility 1.8
sourceCompatibility 1.8
}
}
JDK版本选择1.8
![795730-20170727090002828-1228195489.png](https://i-blog.csdnimg.cn/blog_migrate/abf18ce5cd5b56ad729d3d874fc4b71a.png)
在Eclipse中使用 Lambda 表达式
前提条件
- 1、安装了 JDK 8 的 JRE
- 2、所使用的 Eclipse 要支持 Java8 的编译
在 Eclipse 中,选择 Windows > Preferences > Java > Installed JREs,勾选JDK 8 的 JRE
![](https://images2017.cnblogs.com/blog/795730/201707/795730-20170727090003062-960997347.png)
选择 Windows > Preferences > Java >Compiler,然后将 Compiler compliance level 设为 1.8。如果没有1.8的选项,说明此eclipse版本不支持。
![](https://i-blog.csdnimg.cn/blog_migrate/ac92ecee42f81436dcf60b09d4eb7daa.png)
单击 Apply,然后单击 OK。
![](https://i-blog.csdnimg.cn/blog_migrate/089420f5d82ff873c52084122f0533c7.png)
Eclipse Luna SR2已经添加了对Java8的支持,可直接到官网下载
使用示例
1、没有参数
new Thread(() -> {
Log.i("bqt", "包青天");
//必须有分号}).start();
只有一行语句时,可以进一步简化为:
new Thread(() -> Log.i("bqt", "包青天")).start();
但是如果有多行
语句
,就没法简化了
2、单一参数
listView.setOnClickListener(v -> {
Toast.makeText(ctx, "包青天", Toast.LENGTH_SHORT).show();
//必须有分号});
同样,只有一行语句时,可以进一步简化为:
istView.setOnClickListener(v -> Toast.makeText(ctx, "包青天", Toast.LENGTH_SHORT).show());
3、多个参数
listView.setOnItemClickListener((parent, view, position, id) -> {
Toast.makeText(ctx, "position=" + position, Toast.LENGTH_SHORT).show();
//必须有分号});
同样,
只有一行语句时,
可以进一步简化为:
listView.setOnItemClickListener((parent, view, position, id) -> Toast.makeText(ctx, "position=" + position, Toast.LENGTH_SHORT).show());
常见的不能使用的情况
1、如果有多个需要实现的方法,则不能使用,如:
listView.setOnScrollListener(new AbsListView.OnScrollListener() {
@Override
public void onScrollStateChanged(AbsListView view, int scrollState) {
}
@Override
public void onScroll(AbsListView view, int firstVisibleItem, int visibleItemCount, int totalItemCount) {
}
});
2、如果需要在匿名内部类中定义成员变量,则不能使用,如:
listView.setOnClickListener(new View.OnClickListener() {
private boolean b;
@Override
public void onClick(View v) {
}
});
3、
如果
需要在匿名内部类中使用到this、super等(注意这里的this是指匿名内部类,而非如MainActivity.this这样的外部类)
,则不能使用,如:
view.getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
@Override
public void onGlobalLayout() {
//这里的this代表的是匿名内部类OnGlobalLayoutListener
view.getViewTreeObserver().removeOnGlobalLayoutListener(this);//使用到了this
}
});
演示代码
public class LambdaTestActivity extends ListActivity {
private ImageView iv;
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
String[] array = {"没有参数",
"没有参数,精简模式",
"Runnable + runOnUiThread",
"单一参数",
"方法引用",
"多个参数",
"迭代,方法引用",};
setListAdapter(new ArrayAdapter<>(this, android.R.layout.simple_list_item_1, new ArrayList<>(Arrays.asList(array))));
iv = new ImageView(this);
iv.setImageResource(R.drawable.icon);
getListView().addFooterView(iv);
}
@RequiresApi(api = Build.VERSION_CODES.N)
@Override
protected void onListItemClick(ListView listView, View view, int position, long id) {
switch (position) {
case 0:
new Thread(() -> {
Log.i("bqt", "包青天");
}).start();
break;
case 1:
new Thread(() -> Log.i("bqt", "白乾涛")).start();
break;
case 2:
new Thread(() -> {
//Lambda 主体中的 this、super 引用与封闭上下文中一样,因为 lambda 表达式不会引入新的作用域,这与匿名类不同。
runOnUiThread(() -> Toast.makeText(this, "包青天", Toast.LENGTH_SHORT).show());
}).start();
break;
case 3:
iv.setOnClickListener(v -> Toast.makeText(this, "包青天:" + (v == iv), Toast.LENGTH_SHORT).show());
iv.performClick();
break;
case 4:
iv.setOnClickListener(System.out::println);//方法引用。适用条件:①功能接口方法中的参数是要传到引用方法中作为参数 ②没有返回值
iv.performClick();
break;
case 5:
iv.setOnFocusChangeListener((v, hasFocus) -> Toast.makeText(this, "hasFocus:" + hasFocus, Toast.LENGTH_SHORT).show());
iv.performClick();
break;
case 6:
List<String> list = Arrays.asList("Lambdas", "Default Method", "Stream API", "Date and Time API");
list.forEach(s -> Log.i("bqt", s));//@RequiresApi(api = Build.VERSION_CODES.N)
break;
}
}
}
Lambda 表达式简介
Lambda 表达式也称为闭包,是匿名内部类的简短形式。Lambda 表达式简化了【单一抽象方法声明接口】的使用,因此 lambda 表达式也称为功能接口。
使用 lambda 表达式实现功能接口时,无需创建类或匿名类。
Lambda 表达式只能用于单一方法声明接口,也即
功能接口(只有一个抽象方法的接口)
。
Lambda 表达式具有以下优点:
- 简明的语法
- 方法引用和构造函数引用
- 相比于匿名类,减少了运行时开销
- Lambda 表达式的语法
Lambda 表达式语法
基本语法
(formal parameter list) -> { expression or statements }
参数列表是一个逗号分隔的形式参数列表,这些参数与功能接口中单一方法的形式参数相对应。
参数列表中的参数类型是可选项,如果未指定参数类型,将从上下文推断。
参数列表必须用小括号括起来,但如果只有一个参数且不带参数类型时
小括号
可以省略。
参数列表如果为空(即:功能接口方法没有形式参数),则必须指定空括号。
参数列表后面是 -> 运算符,然后是 lambda 主体,即单一表达式或语句块。
Lambda 主体根据以下选项之一返回结果:
- 如果 lambda 主体是单一表达式,则返回表达式的值(如果有的话)。
- 如果功能接口方法的结果是 void,可以提供一个 return 语句,但这不是必需的。
- 如果功能接口方法具有返回类型,且 lambda 主体不是单一表达式,则 lambda 主体必须使用 return 语句返回匹配的值。
语句块必须包含在大括号内,除非语句块是一个方法调用语句,且
功能接口
方法
的返回结果是void。
Lambda 表达式实际上是一种匿名方法实现,指定形式参数,并使用 return 语句返回值。
匿名方法必须按照以下规则所规定的与其实现的功能接口方法兼容。
- Lambda 表达式返回的结果必须与功能接口方法的结果兼容。返回值的类型可以是功能接口方法声明中返回类型的子类型。
- Lambda 表达式签名必须与功能接口方法的签名相同。
- Lambda 表达式只能抛出那些在功能接口方法的 throws 子句中声明了异常类型或异常超类型的异常。
Lambda 表达式中的局部变量
Lambda 表达式不会定义新的作用域,lambda 表达式的作用域与封闭作用域相同。
如果 Lambda 主体声明的局部变量与封闭作用域内的变量重名,将产生编译器错误
Lambda expression's local variable i cannot re-declare another local variable defined in an enclosing scope
The local variable i may not have been initialized
Variable i is required to be final or effectively final