lambda表达式采用一种简洁的语法定义代码块,它是一个可传递的代码块,可以在声明后执行一或多次。
Java语言传递代码段时需要构造一个对象才能传递该类的方法。
class LengthComparator implements Comparator<String> {
public int compare(String first, String second) {
return first.length()-second.length();
}
}
//调用
Arrays.sort(strings, new LengthComparator());
这里compare方法并不是立即调用。实际上在数组完成排序之前,sort方法会一直调用compare方法,只要元素的顺序不正确就会重新排列元素。这个代码将与其余的排序逻辑集成。为了简化操作出现了lambda表达式:
- 第一种写法
(参数)->表达式
(String first, String second)
->first.length() - second.length()
无需指定返回类型,lambda表达式可以根据上下文推导出返回类型,以上就是int返回类型
- 第二种方法
计算无法由一个表达式实现就要使用
{}
(String first, String second) -> {
if(first.length() < second.length()) return -1;
else if (first.length() > second.length()) return 1;
else return 0;
}
若无参依旧要保留()
() -> { for(int i = 100; i >= 0; i--) System.out.println(i);}
若可以推到出参数类型也可以不写参数类型
Comparator<String> comp
=(first, second)\\可知是String类型
->first.length() - second.length()
若只有一个参数可省略小括号
ActionListener listener = event ->
System.out.println("The time is "
+Instant.ofEpochMilli(event.getWhen()));
函数式接口
对于只有一个抽象方法的接口,需要这种接口的对象时,就可以提供一个lambda表达式,这种接口称为函数式接口。如:
Arrays.sort(words,
(first, second) -> fisrt.length() - second.length());
在底层,Arrays.sort方法会接收实现了Comparator<String>的某个类的对象。在这个对象上调用compare方法会执行lambda表达式的体,这样比较高效。
lambda表达式可以转换为接口,如下:
var time = new Timer(1000, event ->{
System.out.println("At the tone, the time is "
+ Instant.ofEpochMilli(event.getWhen()));
});
BiFunction<T, U, R>,参数类型T和U,返回类型R
方法引用
var time = new Timer(1000, event -> System.out.println(event));
等价于
var time = new Timer(1000, System.out::println);
它指示编译器生成一个函数式接口的实例,覆盖这个接口的抽象方法来调用给定的方法。会生成一个ActionListener,它的actionPerformed(ActionEvent e)方法要调用System.out.println(e)
变量作用域
lambda表达式的三个部分:代码块、参数、自由变量的值(非参数而且不在代码块中定义的量)
lambda表达式可以捕获,但要确保这个值被明确定义,lambda表达式中只能引用值不能改变变量。避免并发时发生不安全的行为。它只能捕获事实最终变量,即初始化后不会再给它赋新值
lambda表达式的体与其嵌套块有相同的作用域