目录
Lambda 表达式
表述:Lambda表达式是Java SE 8中一个重要的新特性。lambda表达式允许你通过表达式来代替功能接口,简化写法。并且只能用来取代函数接口(Functional Interface)的简写。
常用的语法格式
// 1. 不需要参数,返回值为 5
() -> 5
// 2. 接收一个参数(数字类型),返回其2倍的值
x -> 2 * x
// 3. 接受2个参数(数字),并返回他们的差值
(x, y) -> x – y
// 4. 接收2个int型整数,返回他们的和
(int x, int y) -> x + y
// 5. 接受一个 string 对象,并在控制台打印,不返回任何值(看起来像是返回void)
(String s) -> System.out.print(s)
案例一:无参函数(匿名内部类)的简写
public class LambdaDemo01 {
public static void main(String[] args) {
//JDK7 匿名内部类写法
// new Thread(new Runnable() {
// @Override
// public void run() {
// System.out.println("java 8");
// }
// }).start();
//JDK8 Lambda 表达式写法,简化后
new Thread(() ->System.out.println("java 8")).start();
}
}
简化后的代码跟匿名内部类的作用是一样的,但比匿名内部类更进一步。这里连接口名和函数名都一同省掉了。
//这样也可以
// JDK8 Lambda表达式代码块写法
new Thread(
() -> {
System.out.print("Hello");
System.out.println(" Hoolee");
}
).start();
匿名内部类 和 Lambda 的区别 所属类型的不同: - 匿名内部类:可以是接口,也可以是抽象类,还可以是具体类 - Lambda表达式:只能是接口 使用限制不同 - 如果有且仅有一个抽象方法,可以使用 Lambda表达式,也可以使用匿名内部类 - 如果接口中多于一个抽象方法,只能使用 匿名内部类,而不能使用 Lambda 表达式 实现原理的不同 - 匿名内部类:编译之后,产生一个单独的 .class 字节码文件 - Lambda表达式:编译之后,没有一个单独的 .class 字节码文件。对应的字节码会在运行的时候动态生成
案例二:带参函数的简写
// JDK7 匿名内部类写法
List<String> list = Arrays.asList("I", "love", "you", "too");
Collections.sort(list, new Comparator<String>(){ // 接口名
@Override
public int compare(String s1, String s2){ // 方法名
if(s1 == null)
return -1;
if(s2 == null)
return 1;
return s1.length()-s2.length();
}
});
将上述的 Comparator接口的 compare()方法 简化后:
// JDK8 Lambda表达式写法
List<String> list = Arrays.asList("I", "love", "you", "too");
Collections.sort(list, (s1, s2) ->{// 省略参数表的类型
if(s1 == null)
return -1;
if(s2 == null)
return 1;
return s1.length()-s2.length();
});
这里 () -> {} 代替了匿名内部类
上面的代码除了省略了接口名 何 方法名,代码中参数表的类型也省略了。
原因:这得益于javac
的类型推断机制,编译器能够根据上下文信息推断出参数的类型,当然也有推断失败的时候,这时就需要手动指明参数类型了。
注意,Java是强类型语言,每个变量和对象都必需有明确的类型。
案例三:利用lambda表达式对列表进行迭代
/**
* @author That boy
* @date 2022-5-9
* 利用lambda表达式对列表进行迭代
*/
public class LambdaDemo02 {
public static void main(String[] args) {
//利用lambda表达式对列表进行迭代
List<String> list = Arrays.asList("java", "python", "C#", "PHP");
for (int i = 0; i < list.size(); i++) {
System.out.println(list.get(i));
}
//简化后,一行代码搞定
list.forEach(n -> System.out.println(n));
}
}
这里使用了迭代的 forEach()方法 特别方便
案例四:map()统一对元素进行操作简化
import java.util.Arrays;
import java.util.List;
/**
* @author That boy
* @date 2022-5-9
* map()统一对元素进行操作
*/
public class LambdaDemo03 {
public static void main(String[] args) {
List<Integer> list = Arrays.asList(100, 200, 300, 500);
//没简写前
for (int i = 0; i < list.size(); i++) {
double num = list.get(i) * 0.2;
System.out.println(num);
}
//简写后
list.stream().map(n -> n*0.2).forEach(System.out::println);
}
}
这个相当于 案例三的升级版,加了更多的方法
拓展:
System.out::println = 对象::实例方法名
就是把你遍历出来的每一个对象都用来去调用System.out(也就是PrintStream类的一个实例)的println方法。
简写的依据:
-
必须有相应的函数接口 (函数接口,是指内部只有一个抽象方法的接口)
-
类型推断机制
注意:lambda表达式有个限制,那就是只能引用 final 或 final 局部变量,这就是说不能在lambda内部修改定义在域外的变量,刚好对应上述的 内部只有一个抽象方法的接口 。