1、要点概览

  1. 一个lambda表达式是一个带有参数的代码块
  2. 当你想要代码块在以后某个时间点执行时,可以使用lambda表达式
  3. lambda表达式可以被转换为函数式接口
  4. lambda表达式可以在闭包作用域中有效地访问final变量
  5. 方法和构造器引用可以引用方法和构造器,但无须调用它们。
  6. 可以向接口添加默认(default)和静态(static)方法来提供具体的实现。
  7. 必须解决接口中多个默认方法之间的冲突

2、lambda的几种写法

lambda表达式的格式:参数、箭头->、表达式

1. 指明参数类型,表达式没有大括号

(String a, String b) -> Integer.compare(a.length(), b.length())

2. 指明参数类型,表达式使用大括号

(String a, String b) -> {
	if (a.length() < b.length()) return -1;
	else if (a.length() > b.length()) return 1;
	else return 0;
}

3. 可以没有输入参数

() -> {
	for (int i = 0; i < 10; i++) {
		doSomething();
	}
}

4. 参数类型可以推导得知时,可以省略类型声明;如果只有一个参数,可以省略括号
如下示例,可知list元素类型均为String类型,故可省略类型声明String

List<String> list = Arrays.asList("a", "b", "c");
list.stream().filter((String x) -> StringUtils.isNotBlank(x)).collect(Collectors.toList());

list.stream().filter((x) -> StringUtils.isNotBlank(x)).collect(Collectors.toList());

list.stream().filter(x -> StringUtils.isNotBlank(x)).collect(Collectors.toList());

5. 参数可以添加注解或者final修饰符

(final String x) -> {}
(@NonNull String x) -> {}

3、函数式接口

对于只包含一个抽象方法接口,可以通过lambda表达式来创建该接口的对象。示例如下:

Arrays.sort(list, (x, y) -> Integer.compare(x.length(), y.length()));

该方法的第二个参数需要一个Comparator接口(该接口只有一个抽象方法)的实例。

可以在任意函数式接口上标注@FunctionalInterface注解,这样做有两个好处。首先,编译器会检查标注该注解的实体,检查该接口是否只包含一个抽象方法。另外,在javadoc页面也会包含一条声明,说明这个接口是一个函数式接口。

当一个lambda表达式被转换为一个函数式接口的实例时,请注意处理检查期异常。

4、方法引用

::操作符将方法名和对象或类的名字分隔开,有三种使用情况

对象::实例方法
类::静态方法
类::实例方法

示例1:

button.setOnAction(System.out::Println);

等同于

button.setOnAction(x -> System.out.println(x));

示例2:

Arrays.sort(arr, String::compareToIgnoreCase);

等同于

Arrays.sort(arr, (x, y) -> x.compareToIgnoreCase(y));

示例3:捕获方法引用中的this参数
this::equals <===> x -> this.equals(x)

在匿名类中,可以调用一个闭合类或父类的员工方法,如 闭合类.this::方法 或者 闭合类.super::方法。

5、构造器引用

labels.stream().map(Button::new).collect(Collectors.toList());

水平有限,后期会继续补充完善。