lambda表达式

268 阅读2分钟

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>,参数类型TU,返回类型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表达式的体与其嵌套块有相同的作用域