简介

在JDK8中,Java引入了一个重要特性,主要用于简化代码,尤其是在处理函数式编程时🤔

函数式接口(Functional Interface)

Java的lambda表达式必须依赖函数式接口,一个函数式接口只能有一个抽象方法,使用@FunctionalInterface注解来标记一个接口为函数式接口

1
2
3
4
5
6
7
8
9
10
11
12
@FunctionalInterface
interface MyFunctionalInterface {
void execute();

default void defaultMethod() {
System.out.println("This is a default method");
}

static void staticMethod() {
System.out.println("This is a static method");
}
}

lambda表达式

当在使用一些方法,方法要求传入一个函数式接口的实现类对象时,便可以使用lambda表达式去简写这个对象,假设现在有一个需求:

给定一个名单列表,使用Stream流来筛选剩下名字开头为A的,并将名字转换成大写输出

1
2
3
4
5
6
List<String> names = Arrays.asList("Alice", "Bob", "Charlie", "David");

names.stream()
.filter(name -> name.startsWith("A")) // 过滤名字以 "A" 开头的元素
.map(String::toUpperCase) // 转换为大写
.forEach(System.out::println); // 打印结果

lambda表达式可以有三种不同的形式:

  • 无参数,无返回值
    1
    () -> System.out.println("Hello, World");
  • 有参数,无返回值
    1
    (int x, int y) -> System.out.println(x + y);
  • 有参数,有返回值
    1
    (int x, int y) -> { return x + y; };

简写:

  1. 如果只有一个参数,可以省略小括号
    1
    str -> System.out.println(str);
  2. 如果表达式体只有一个语句,可以省略大括号和return关键字
    1
    (x, y) -> x + y; // 等价于 (x, y) -> { return x + y; }
  3. 在使用 lambda 表达式时,编译器会根据上下文自动推断参数的类型,所以可以省略参数类型
    1
    Comparatpr<Integer> cpr = (a, b) -> a.compareTo(b);

方法引用(Method References)

方法引用是lambda表达式的简化形式,它直接引用现有的方法

  1. 引用静态方法
    语法:类名::方法名
    1
    2
    Consumer<Integer> print = System.out::println;
    print.accept(123);
  2. 引用其他类成员方法
    语法:对象::方法
    1
    2
    3
    String str = "Hello";
    Supplier<Integer> length = str::length;
    System.out.println(length.get());
  3. 引用本类成员方法
    语法:this::方法
  4. 引用父类成员方法
    语法:super::方法
  5. 引用构造方法
    语法:类名::new
    1
    2
    Supplier<List<String>> listSupplier = ArrayList::new;
    List<String> list = listSupplier.get();

lambda表达式的局部变量捕获

在lambda表达式中,可以访问局部变量,但是这些变量必须是隐式final的,也就是说不能够在lambda表达式外修改它们

1
2
3
int num = 10;
Consumer<Integer> consumer = x -> System.out.println(x + num);
// num = 11; // 这样会报错,因为 `num` 必须保持不变