Lambda 表达式

(参数列表)> { 代码语句 }
// Lambda表达式的书写形式
Runnable run = () -> System.out.println("Hello World");// 1
ActionListener listener = event -> System.out.println("button clicked");// 2
Runnable multiLine = () -> {// 3 代码块
    System.out.print("Hello");
    System.out.println(" Hoolee");
};
BinaryOperator<Long> add = (Long x, Long y) -> x + y;// 4
BinaryOperator<Long> addImplicit = (x, y) -> x + y;// 5 类型推断
  • 类似于匿名方法,一个没有名字的方法
  • 可以忽略写参数类型
  • 坚决不声明返回值类型
  • 没有修饰符
  • 单句表达式,将直接返回值,不用大括号
  • 带return语句, 算多句,必须用大括号
  • 无参数,仅保留括号
  • 一个参数,可省略括号

使用前提

  • 使用Lambda必须具有接口,且要求接口中有且仅有一个抽象方法(称之为函数式接口)。 无论是JDK内置的 Runnable 、 Comparator 接口还是自定义的接口,只有当接口中的抽象方法存在且唯一 时,才可以使用Lambda。
  • 使用Lambda必须具有上下文推断。 也就是方法的参数或局部变量类型必须为Lambda对应的接口类型,才能使用Lambda作为该接口的实例。

有且仅有一个抽象方法的接口,称为"函数式接口"。

函数式接口

  • 是一个接口,符合Java接口的定义
  • 只包含一个抽象方法的接口
  • 可以包括其他的default方法、static方法、private方法
  • 由于只有一个未实现的方法,所以Lambda表达式可以自动填上这个尚未实现的方法
  • 采用Lambda表达式,可以自动创建出一个(伪)嵌套类的对象(没有实际的嵌套类class文件产生),然后使用,比真正嵌套类更加轻量,更加简洁高效

  • @FunctionalInterface注解

一旦使用该注解来标记接口,编译器将会强制检查该接口是否确实有且仅有一个抽象方法,否则编译将会报错。

@FunctionalInterface
public interface SuperRunnable {
    void superRun();
}
public static void main(String[] args) {
    superRun(()-> System.out.println("hello world"));
}
private static void superRun(SuperRunnable sr){
    sr.superRun();
}
  • 尽量使用系统自带的函数式接口,不要自己定义
接口 参数 返回值 示例
Predicate < T > T Boolean 接收一个参数,返回一个布尔值
Consumer < T > T void 接受一个参数,无返回
Function < T, R > T R 接受一个参数,返回一个值
Supplier < T > None T 无参数 返回一个值

Lambda JVM层实现

Java编译器将Lambda表达式编译成使用表达式的类的一个私有方法,然后通过invokedynamic指令调用该方法。所以在Lambda表达式内,this引用指向的仍是使用表达式的类。

方法引用

  • Class::staticMethod,如 Math::abs方法
    • Math::abs 等价于 x -> Math.abs(x)
  • Class::instanceMethod,如String::compareToIgnoreCase方法
    • String::compareToIgnoreCase等价于(x,y)->x.compareToIgnoreCase(y)
  • object::instanceMethod,如System.out::println方法
    • System.out::println等价于x->System.out.println(x)
    • 支持this::instanceMethod 调用
    • 支持super::instanceMethod 调用
  • Class::new,调用某类构造函数,支持单个对象构建
    • Supplier < Object > sp = Object::new
  • Class[]::new,调用某类构造函数,支持数组对象构建
    • Function < Integer,Object > f = Object[]::new

应用

  • 类型信息
    • 被赋值后,可以看作是一个函数式接口的实例(对象)
    • 但是Lambda表达式没有存储目标类型(target type)的信息
    • 重载调用,依据重载的规则和类型参数推理
  • 变量遮蔽
    • Lambda表达式可以访问外部嵌套块的变量
      • 但是变量要求是final或者是effectively final的
    • 在Lambda表达式中,不可以声明与(外部嵌套块)局部变量同名的参数或者局部变量
  • 表达式中的this,就是创建这个表达式的方法的this参数
  • 优先级比嵌套类要高
    • 无法创建命名实例,无法获取自身的引用(this)
  • 方法引用比自定义Lambda表达式的优先级高
    • 系统自带的方法引用更简洁高效
    • 对于复杂的Lambda表达式,采用方法引用比内嵌Lambda表达式更清晰,更容易维护
  • 坚持使用标准的函数式接口

results matching " "

No results matching " "

results matching " "

No results matching " "