skip to content

Search

Lambda

4 min read Updated:
奶牛小狗

Lambda表达式,函数式接口,方法引用

Lambda表达式

Lambda不是函数,而是对象

(a, b) -> a.length() - b.length()本身没有类型。当作为参数传递,编译器根据上下文将它转化为某个函数式接口的实例对象

函数式接口是只包含一个抽象方法的接口

例如

List<String> words = Arrays.asList("apple", "pie", "banana");
 
words.sort((a, b) -> a.length() - b.length());

此时编译器将(a, b) -> a.length() - b.length()转化为Comparator<String>的实例对象

// 等效的匿名内部类
words.sort(new Comparator<String>() {
    @Override
    public int compare(String a, String b) {
        return a.length() - b.length();
    }
});

函数式接口

java.util.function包中提供了大量的函数式接口

一个函数式接口描述了一种函数,可以将对应的Lambda表达式转化为该函数式接口的实例对象

例如Consumer<T>表示一个接受一个参数并且没有返回值的函数

Consumer<String> printer = s -> System.out.println(s);

这个语句等价为

Consumer<String> printer = new Consumer<String>() {
    @Override
    public void accept(String s) {
        System.out.println(s);
    }
};

方法引用

方法引用是lambda表达式的一种简写形式,它允许你直接引用一个已存在的方法

方法引用可以分为四种类型:

方法引用类型具体示例(方法引用)等价的 Lambda 表达式
静态方法引用Math::max(a, b) -> Math.max(a, b)
特定对象的实例方法引用System.out::println(s) -> System.out.println(s)
特定类的任意对象实例方法引用String::length(s) -> s.length()
构造方法引用ArrayList::new() -> new ArrayList<>()
  • this::instanceMethod 等价于(args) -> this.instanceMethod(args)
  • super::instanceMethod 等价于(args) -> super.instanceMethod(args)

闭包

Lambda 可以访问外部局部变量,但该变量必须是 effectively final(实际上不可变)

lambda 捕获外部局部变量时,存的是该 变量的值副本(如果是引用类型,这个值就是引用地址)。这样设计避免了因修改变量本身而造成的语义混乱,因此要求变量必须是 effectively final

但是对于实例字段,Lambda只捕获了 this 引用,字段修改不受限制

对于引用类型的局部变量,Lambda捕获的是引用的副本,修改引用指向的对象不受限制,但不能修改引用本身