Java Lambda表达式的箭头理解总结
文章目录
下面就是一段lambda表达式,如果一脸懵逼的,可以在这里学习一下。
//示例1:lambda表达式排序
String[] players = {"11", "22", "99", "88", "55"};
Arrays.sort(players, (String s1, String s2) -> (s1.compareTo(s2)));
//示例2:系统源码中的一段示例:
Executor mExecutor = XXX;
mExecutor.execute(() -> mSoftApListener.onConnectedClientsChanged());
//示例3:系统源码中的一段示例:
IWifiIface iface = XXX;
iface.getName((WifiStatus status, String name) -> {
if (status.code == WifiStatusCode.SUCCESS) {
nameResp.value = name;
} else {
Log.e(TAG, "Error on getName: " + statusString(status));
}
});
从上面代码可以看到,lambda表达式是在方法参数中写入一大串代码。
之前也是看过lambda,但是有时候看系统源码发现里面的方法有点懵逼,所以有必要进行总结一下。
一般我写代码是不会用lambda表达式的,虽然代码简洁了,但是感觉写得有点抽象了。
并且要写成Lambda表达式要对参数对象非常熟悉,比如实现方法中的回调参数有几个,是否需要返回值。
并不是所有的方法都可以写成Lambda表达式,
必要条件是方法的参数有对象,并且这个对象new的时候必须实现里面的一个方法。
Lambda表达式简单理解就是省略了new的过程和回调方法。
Lambda表达式箭头->理解就是:
箭头前面是回调方法的参数
箭头后面是回调方法需要返回的值或者需要执行的操作。
一、简单的Lambda的基础知识点:
1. 无参数,返回值为 5
() -> 5
方法参数对象的实现方法无回调参数,并且需要返回一个int值。
2. 接收一个参数(数字类型),返回其2倍的值
x -> 2 * x
方法参数对象的实现方法有一个回调参数,并且需要返回回调参数的两倍。
3. 接受2个参数(数字),并返回他们的差值
(x, y) -> x – y
方法参数对象的实现方法有两个回调参数,并且需要返回回调参数的x-y。
// 4. 接收2个int型整数,返回他们的和
(int x, int y) -> x + y
方法参数对象的实现方法有两个回调int(可省略)参数,并且需要返回回调参数的x-y。
比如示例1 的代码。就是基于这个知识点。
// 5. 接受一个 string 对象,并在控制台打印,不返回任何值(看起来像是返回void)
(String s) -> System.out.print(s)
方法参数对象的实现方法有一个回调String(可省略)参数,无需返回值,可执行其他操作比如加个打印。
实现方法无返回值时,可以使用{}并且在里面执行多条语句,比如示例3 的代码,就是基于这个知识点。
上面就是Lambda表达式的基础知识,可以看不懂没关系,通过下面的示例就可以理解这些知识点了。
其实就四种情况,参数对象的回调方法中参数有无的情况和回调方法有无返回值的情况。
箭头前面是针对参数对象的回调方法中参数情况,箭头后面是针对回调方法有无返回值的情况。
二、Lambda 表达式示例
1、实现方法没有参数,无返回值的情况
普通线程Thread执行Lambda表达式写法对比:
//普通的Java表达式:
new Thread(new Runnable() {
@Override
public void run() {
Log.i("TAG", "test Thread");
}
}).start();
//Lambda表达式,打印一个日志
new Thread(()->Log.i("TAG", "test Thread")).start();
这里可以看到Lambda表达式就是省略了参数对象中的匿名类的创建和里面的回调方法。
这样看代码是简洁了很多;
其实想想这个写法也是比较合理的,
因为我们调用者阅读的时候并不需要知道这个匿名类和回调方法,
只需要知道有个回调,并且需要在里面做些事情。
2、实现方法有参数,无返回值的情况
Android 控件点击事件Lambda表达式写法对比:
TextView textView = new TextView(this);
//普通的Java表达式:
textView.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
Log.i("TAG", "test");
}
});
//Lambda表达式,打印一个日志
textView.setOnClickListener((View view) -> Log.i("TAG", "test")); //这里也可以用{}执行多个命令
//Lambda表达式,执行多行命令
textView.setOnClickListener(view -> {
Log.i("TAG", "test");
Log.i("TAG", "test2");
});
值得注意的是这里的参数可以直接定义参数名,也可以加上参数类型。
View view ->… 和view ->…是同一个意思,
多个参数的时候,加上个参数类型可以方便区分。
3、实现方法有参数,有返回值的情况
对数组数据进行从小到大排序写法。
List<String> players = {"11", "22", "99", "88", "55"};
// 1.1 使用匿名内部类根据 name 排序 players
Comparator<String> comparatorName = new Comparator<String>() {
@Override
public int compare(String s1, String s2) {
return (s1.compareTo(s2));
}
};
Arrays.sort(players, comparatorName);
// 1.2 使用 lambda expression 排序 players
comparatorName = (String s1, String s2) -> (s1.compareTo(s2));
//如果需要执行多个语句并且需要返回值,可以用{}并在里面进行return。
comparatorName = (String s1, String s2) -> {
Log.i("TAG", "test compareTo");
return s1.compareTo(s2);
};
Arrays.sort(players, comparatorName);
// 1.3 也可以采用如下形式:
Arrays.sort(players, (s1, s2) -> (s1.compareTo(s2)));
// 1.4 也可以采用如下形式:
Arrays.sort(players, String::compareTo);//这个特殊写法记忆一下就行
这里看到看到多个参数监听前面是要写在()内的,可以一个参数不声明类型的时候箭头前面可以不用()。
学习了上面的代码示例,再慢慢琢磨一下,基本Lambda表达式的->就没啥阅读障碍了。
下面再最后总结一下Lambda箭头的理解:
1、Lambda表达式必定有方法的参数是一个对象的情况,并且new这个对象有必须实现的方法。
2、Lambda表达式就是省略了参数对象中的匿名类的创建和里面的回调方法名,方法参数类型也可以省略;
3、Lambda表达式箭头->前面是回调方法的参数,箭头->后面是回调需要返回的值或者需要是回调方法需要执行的代码;
4、方法参数对象回调方法,如果回调方法没有参数就用()写在箭头->前面
如果回调方法的参数有一个或者多个就在()里面,参数类型可写可不写;
需要注意的是要么全部不要参数类型,要么全部带参数类型,否则会报错;
5、方法参数对象回调方法,如果直接返回一个值或者执行一条代码写在箭头->后面即可
如果回调方法中需要执多行代码,可以把代码写在{}里面。
上面就是这个Lambda的大致使用情况总结了。
认真看一下上面的总结,之后一个方法有多个箭头->的情况也不会懵逼了;
慢慢分析里面的关系就好了,实际情况中也会有方法的参数中有参数对象,
而参数对象的回调方法执行的代码中还有Lambda表达式,
或者多个参数的情况,一步步分析也是没有问题的。
但是也有有一些特例,这个需要简单记忆一下就行。
其他
1、Lambda表达式中的列表数据打印
String[] atp = {"Rafael Nadal", "Novak Djokovic", "Stanislas Wawrinka"};
List<String> players = Arrays.asList(atp);
// 以前的循环方式
for (String player : players) {
System.out.print(player + "; ");
}
// 使用 lambda 表达式以及函数操作(functional operation)
players.forEach((player) -> System.out.print(player + "; "));
// 在 Java 8 中使用双冒号操作符(double colon operator)
players.forEach(System.out::println);
Android中基本不会用System,所以这个没啥用。
2、Lambda表达式中如果不需要返回值,但是代码中直接返回一个数值(比如:->5),会怎么样?
这个是会编译报错,就是不允许这样写,
要么你写成->{} //执行空操作
要么你写成->method() //执行一个方法,不管这个方法有没有返回值都可以正常编译