【Lambda 表达式】简单上手版

98 阅读2分钟

本文已参与「新人创作礼」活动,一起开启掘金创作之路。

一、前提

  • 只有在接受函数式接口的地方才可以使用Lambda 表达式

函数式接口@FunctionalInterface 注解用于表示该接口会设计成一个函数式接口

  • 在 Lambda 主体中引用的局部变量必须使用 final 修饰。 具体原因: 请跳转
()->{ 
    final String str='';
    return str;
}

二、方法引用

  • 静态方法的方法引用:args -> ClassName.staticMethod(args) 等价 ClassName::staticMethod
  • 实例方法的方法引用:args -> expr.instanceMethod(args) 等价 expr::instanceMethod
  • 构造函数引用:new Test() 等价 ClassName::new
public class Test {
    public Test() {
    }

    public static int staticMethod(int num) {
        return num + 1;
    }

    public int instanceMethod(int num) {
        return num - 1;
    }
}

public static void main(String[] args){
    List<Integer> list = Arrays.asList(1, 2, 3);
    //静态方法
    list.stream().map(Test::staticMethod).collect(Collectors.toList());
    //实例方法
    Test test = new Test();
    list.stream().map(test::staticMethod).collect(Collectors.toList());
}

三、使用

@FunctionalInterface
public interface text{
    int test(int a);
}

public static void main(String[] args){
    text t = null;
    //第一种使用方式
    t = (a) -> 1;
   
    //第二种使用方式
    t = a -> a + 1;
    
    //第三种使用方式
    t = (int a) -> {
        return a - 1;
    };
}

四、一些解释

1、为什么 Lambda 主体中引用的局部变量必须使用 final 修饰

  • 有效 final 变量的限制禁止对动态更改的本地变量(局部变量)的访问,捕获本地变量可能会引入并发问题

例子1:如果你认为流是对每个值求和2,但实际上它是对0求和,因为这是执行lambda时可用的最新值

public int workaroundSingleThread() {
    int[] holder = new int[] { 2 };
    IntStream sums = IntStream
            .of(1, 2, 3)
            .map(val -> val + holder[0]);

    holder[0] = 0;
    return sums.sum();
}

例子2:编译不通过,start是一个局部变量,而且必须是final修饰,因为start值是不能变的,不然在lambda内部递增 start 实际上可以修改 start 方法参数

Supplier<Integer> incrementer(int start) {
  return () -> start++;
}