一帆磨砺

生活所迫,一叶孤舟

0%

Java版本特性-Lambda

引用参考文档链接

  1. Oracle官方Lambda文档
  2. GitHub-CarpenterLee-JavaLambdaInternals

    Lambda

模型

1
LambdaParameters -> LambdaBody

参数

无入参案例
JDK7匿名内部类版本:
1
2
3
4
5
6
new Thread(new Runnable() {
@Override
public void run(){
System.out.println("启动");
}
}).start();
JDK8 Lambda版本:
1
new Thread(() -> System.out.println("起飞")).start();
一个入参案例
自定义接口类
1
2
3
public interface LambdaSingleParam {
public void test(int i);
}
自定义调用类
1
2
3
4
5
public class LambdaFuncAccepter {
public static void testFunc(LambdaSingleParam lambda) {
lambda.test();
}
}
JDK7 匿名类版本
1
2
3
4
5
6
LambdaFuncAccepter.testFunc(new LambdaSingleParam() {
@Override
public void test(int i) {
System.out.println(i);
}
});
JDK8 Lambda版本
1
2
3
4
5
LambdaFuncAccepter.testFunc((LambdaSingleParam) System.out::println);
// 当接收lambda表达式的类存在重载时,才需要显示的强转辅助编译器确认调用函数
// 当不存在重载时,直接可以使用 LambdaFuncAccepter.testFunc(System.out::println);
// 单个参数场景下的 System.out.println(i); 可以简写为 System.out::println
// 一般情况下,表达式类似于 a -> System.out.println(a); 参数的() 可以省略
多入参案例
自定义接口类
1
2
3
public interface LambdaMultipleParams {
public void test(int x, int y);
}
自定义调用类
1
2
3
4
5
public class LambdaFuncAccepter {
public static void testFunc(LambdaMultipleParams lambda) {
lambda.test(1, 2);
}
}
JDK7 匿名类版本
1
2
3
4
5
6
LambdaFuncAccepter.testFunc(new LambdaMultipleParams() {
@Override
public void test(int x, int y) {
System.out.println(x + y);
}
});
JDK8 Lambda版本
1
2
LambdaFuncAccepter.testFunc((a, b) -> System.out.println(a + b));
// 多参数场景下,入参的 '()' 必须存在

方法体

单条执行语句
无return案例

同无入参案例

有return案例
1
2
3
4
5
6
7
8
public interface LambdaWIthReturnNoParam {
public int test();
}

...
// () -> 233 ,其中return可以省略
LambdaWIthReturnNoParam lambdaWIthReturnNoParam = () -> 233;
System.out.println(lambdaWIthReturnNoParam.test());
多条执行语句
无return案例
1
2
3
4
5
6
7
// 使用runable接口
// 多条执行语句的方法体必须使用 { } 包裹
// 语法规则基本与正常函数方法体一致
new Thread(() -> {
System.out.println("line1");
System.out.println("line2");
}).start();
有return案例
1
2
3
4
5
6
7
8
// 使用 LambdaWIthReturnNoParam 接口
// return 也属于执行语句
// 多条语句场景 return 不可省略
LambdaWIthReturnNoParam lambdaWIthReturnNoParam = () -> {
System.out.println("line1");
return 2022;
};
System.out.println(lambdaWIthReturnNoParam.test());

注意事项

  1. lambda表达式的使用必须要有对应的函数接口,并且该接口有且仅有一个无默认实现的函数(当接口的其他函数均由默认实现时,该接口也可使用lambda,如Comparator)
    1
    2
    3
    4
    Integer[] a = {1, 2, 3, 4, 5, 6, 7, 8, 9};
    Arrays.sort(a, (o1, o2) -> o2 - o1);
    // 也可写成,不过Integer内置是固定升序的,无法修改
    Arrays.sort(a, Integer::compare);
  2. 多参数场景下,要么都声明入参类型,要么都不声明,不允许一部分声明,一部分隐藏
    1
    2
    LambdaFuncAccepter.testFunc((a, int b) -> System.out.println(a + b));
    // 此时编译器会报错
  3. final 不能修饰推断类型入参,如需使用final,需要将入参显示设置类型
    1
    2
    3
    4
    // 编译器会提示异常
    LambdaFuncAccepter.testFunc((a, final b) -> System.out.println(a + b));
    // 需调整为如下所示:
    LambdaFuncAccepter.testFunc((int a, final int b) -> System.out.println(a + b));
  4. lambda方法体使用外部变量时,必须遵守声明时赋值后续不可赋值规则(同final修饰规则),但调用对象函数修改对象内部状态合法
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    StringBuilder sb = new StringBuilder();
    new Thread(() -> {
    // Variable used in lambda expression should be final or effectively final
    // 虽然sb没有被final声明,但是在lambda内部存在隐形的final限制
    // sb = new StringBuilder();
    sb.append(111);
    System.out.println("line1");
    }).start();

    int y = 1;
    // 即便是在外部在初始化后再修改赋值,此时已经破坏final规则
    y = 3;
    new Thread(() -> {
    // Variable used in lambda expression should be final or effectively final
    System.out.println(y);
    }).start();
  5. 使用数组一类时,需要注意下标的使用,如下
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    int[] b = {1, 2, 3};
    for (int i = 0; i < b.length; i++) {
    new Thread(() -> {
    // Variable used in lambda expression should be final or effectively final
    // 此时 i 不是遵守final规则的变量
    System.out.println(b[i]);
    }).start();
    }
    // 可以修改调整如下所示:
    for (int i : b) {
    new Thread(() -> {
    // 此时变量i作为临时变量还尚未经历再一次的赋值修改,因此还遵守 effectively final 规则
    System.out.println(i);
    }).start();
    }
  6. lambda方法体使用外部变量时,必须确保所有外部变量均以完成初始化(仅声明不行,如分支,必须确保变量初始化)
    1
    2
    3
    4
    5
    6
    7
    8
    int x;
    if (sb.length() > 5) {
    x = 1;
    }
    new Thread(() -> {
    // Variable 'x' might not have been initialized
    System.out.println(x);
    }).start();

欢迎关注我的其它发布渠道