区别如下:
Lambda表达式长这样:
````
lambda表达式的形式如下:
````
parameters -> expression
或者
parameters -> { block }
在 lambda 中,block
可以返回一个值,或者对于类似 void
的行为不返回任何值。
换句话说,如果 expression
具有非 void 类型,则 parameters -> expression
lambda 相当于 parameters -> { return expression; }
;如果 expression
具有 void 类型(例如 System.out.printf()
),则相当于 parameters -> { expression; }
。
你的第一个版本实际上使用了一些额外的开销:
i -> i = i * 2
可以简化为 i -> i * 2
,因为 i =
赋值是多余的,i
在之后立即消失而没有被进一步使用。
这就像
Integer function(Integer i) {
i = i * 2;
return i;
}
或者
Integer function(Integer i) {
return (i = i * 2);
}
可以简化为:
Integer function(Integer i) {
return i * 2;
}
所有这些例子都符合接口
UnaryOperator<Integer>
,它是
Function<Integer, Integer>
的特殊情况。
相比之下,你的第二个例子就像...
XY function(int i) {
i = i * 2;
}
无效的代码:
- 要么
XY
是 void
(这将产生一个不符合 .map()
的 Consumer<Integer>
)
- 要么
XY
确实是 Integer
(那么缺少返回语句)。
那个值有什么必要吗(除了使代码编译)?
好吧,.forEach(System.out::println);
需要那个值...
因此,所有可以转换为 Function<T, R>
的内容都可以提供给 T
流的 .map()
,从而得到一个 R
流:
Stream.of(1, 2, 3).map(i -> i * 2)
Stream.of(1, 2, 3).map(i -> { return i * 2; })
将您提供的“整数(Integer)”转换为另一个“整数(Integer)”,并给您另一个“流(Stream)<整数(Integer)>”。您注意到它们是装箱的吗?
其他方法包括:
Stream.of(1, 2, 3).mapToInt(i -> i * 2)
Stream.of(1, 2, 3).mapToInt(i -> { return i * 2; })
IntStream.of(1, 2, 3).map(i -> i * 2)
IntStream.of(1, 2, 3).map(i -> { return i * 2; })
IntStream.of(1, 2, 3).mapToObj(i -> i * 2)
IntStream.of(1, 2, 3).mapToObj(i -> { return i * 2; })
所有这些例子的共同点是它们获取一个值并生成相同或不同类型的值。(注意这些示例根据需要使用自动装箱和自动拆箱。)
另一方面,任何可以转换为
Consumer<T>
的内容都可以提供给
T
流的
.map()
,它可以是任何形式的lambda表达式,该表达式生成一个
void
表达式:
.forEach(x -> System.out.println(x))
.forEach(x -> { System.out.println(x); })
.forEach(System.out::println)
.forEach(x -> { })
有了这个想法,很容易看出带有 void
表达式类型的 Lambda 无法传递给 .map()
,而带有非 void
类型的 Lambda 也无法传递给 forEach()
。