Java 8 的 Lambda 表达式的实现方式还是基于已有的字节码指令,由 Lambda 表达式的方法签名结合上下文并经由 SAM 推断出正确的类型来。Java 8 的 Lambda 完整书写格式是
(type parameter1 [type parameter2, ...type parametern]) -> { statements here }
这种标准格式所表示的就是方法签名。
虽不及其他语言的 Lambda 表达式,像 Swift, Scala 可省略参数部分,可用默认参数名 $0
, $1
, 或 _
, 但 Java 8 的 Lambda 还是可以进行酌情简化
- 参数类型总是可省略 --
(x, y) -> { x + y; }
- 参数为一个时,参数括号可省略 --
x -> { System.out.println(x); }
- 语句为一条时,可省略大括号, 并且语句后不要分号 --
x -> System.out.println(x)
- 上面更进一步,如果是单条 return 语句,必须把 return 关键字去掉 --
x -> "Hello " + x
- 就差一点,参数部分总是不能省,无参必须写成
() -> System.out.println("hi")
- Java 8 中若要近似的实现无参数部分写法,那就是方法引用了 --
System.out::println
. 参数类型总是可省略, 基本上我们总是省略掉参数类型
1 2 3 4 5 6 7 8 9 10 11 12 |
interface Function { void call(String x, String y); } void foo(Function f) { f.call("a", "b"); } foo((x, y) -> { //(x, y) 完整写法是 (String x, String y) System.out.println(x); System.out.println(y); }); |
. 参数为一个时,参数括号省略
1 2 3 4 5 6 7 8 9 |
interface Function { void call(String x); } Function f = x -> { System.out.println(); System.out.println(x); }; f.call("Hello"); |
. 语句为一条时,可省略大括号, 并且语句后不要分号
1 2 3 4 5 6 7 8 9 |
interface Function { void call(String x); } void foo(Function f) { f.call("Hi"); } foo(x -> System.out.println(x)); //不能写成 foo(x -> System.out.println(x);); 这像话 |
. 如果是单条 return 语句,省去大括时必须把 return 关键字去掉
1 2 3 4 5 |
interface Function { void String call(String x); } foo(x -> "Hello " + x) |
. 参数部分的括号总是需要
1 2 3 4 5 |
interface Function { void call(); } Function f = () -> System.out.println(); |
不写出 ->
来似乎不知道这是一个 Lambda.
Java 8 中目前还无法简化成类似于 Swift/Scala 中的 foo(System.out.println()) 或 foo {System.out.println()}。不过可以采用方法引用的方式,只是方法引用有其缺陷--不能捕获外部变量。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 |
public class TestLambda { public static void main(String[] args) { foo(TestLambda::todo); //todo 方法的签名正好是 x -> String } static void foo(Function f){ System.out.println(f.call("World")); } static String todo(String x) { //也就是这个方法正好符合 Function 的 SAM 方法签名 return "Hello " + x; } } interface Function { String call(String x); } |
前面说过用方法引用的缺陷是无法捕外部变量,譬如用 Lambda 的方式
1 2 |
String external = "ABC"; foo(x -> external + x); |
而在前面的 todo 方法中却访问不到 external 变量,如果给 todo 再增加一个参数来传递 external 则不符合 Function 的 SAM 的签名了。
除非,除非用实例的方法引用,那么需要每次传入外部参数来构造实例,例如这样
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 |
public class TestLambda { public static void main(String[] args) { String external = "ABC"; foo(new MethodProvider(external)::todo); //输出 Hello ABC World } static void foo(Function f){ System.out.println(f.call("World")); } } class MethodProvider { private String _external; public MethodProvider(String external) { this._external = external; } String todo(String x) { return "Hello " + _external + " " + x; } } interface Function { String call(String x); } |
这样着实有些怪异,而且有点把欲作简化的东西复杂化了。
本文链接 https://yanbin.blog/java-8-lambda-simple-ways/, 来自 隔叶黄莺 Yanbin Blog
[版权声明] 本文采用 署名-非商业性使用-相同方式共享 4.0 国际 (CC BY-NC-SA 4.0) 进行许可。