昨天我偶然发现了一些我既不理解也无法找到解释的东西:
考虑以下操作:
Stream.of(1, 2, 3).map(i -> i * 2).forEach(System.out::println);
//This one won't compile
Stream.of(1, 2, 3).map(i -> { i * 2; }).forEach(System.out::println);
似乎第二个可以扩展到
Stream.of(1, 2, 3).map(i -> { return i * 2;}).forEach(System.out::println);
它只会编译好。我想出了这个,因为我已经习惯了第一个版本,但我的IDE(Netbeans)总是指最后一个版本。
所以我的问题是: 这两种实现的区别/优势是什么?为什么带有{}
块的那个需要返回值?需要该值的位置(编译代码除外)?
更新
关于When are braces optional in Java 8 lambda syntax?,这个不能仅仅因为
而与lambda表达式语法有关Stream.of(1, 2, 3).forEach(i -> { System.out.println(i); });
编译好,所以必须(从我的描述)关于map()
的实现。
干杯,本
答案 0 :(得分:9)
不同之处如下:
lambda表达式看起来像
parameters -> expression
或
parameters -> { block }
其中block
返回一个值 - 或者它不像void
那样行为。
换句话说,如果parameters -> expression
具有非空类型,则parameters -> { return expression; }
lambda等同于expression
;如果parameters -> { expression; }
具有void类型,则expression
等同于System.out.printf()
(例如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
为Consumer<Integer>
(这会使.map()
与[{1}}不相符)XY
确实是Integer
(然后缺少return语句)。需要该值的位置(编译代码除外)?
嗯,.forEach(System.out::println);
需要那个价值......
因此,可以转换为Function<T, R>
的所有内容都可以提供给.map()
的{{1}}信息流,从而产生T
信息流:
R
将您提供的Stream.of(1, 2, 3).map(i -> i * 2)
Stream.of(1, 2, 3).map(i -> { return i * 2; })
转换为另一个Integer
,再为您提供Integer
。你注意到它们是盒装的吗?
其他方式
Stream<Integer>
所有这些例子都有一个共同点,就是它们得到一个值并产生相同或不同类型的值。 (注意这些示例如何根据需要使用AutoBoxing和AutoUnboxing。)
OTOH,可以转换为// turn a Stream<Integer> to an IntStream with a
// int applyAsInt(Integer i) aka ToIntFunction<Integer>
Stream.of(1, 2, 3).mapToInt(i -> i * 2)
Stream.of(1, 2, 3).mapToInt(i -> { return i * 2; })
// turn an IntStream to a different IntStream with a
// int applyAsInt(int i) aka IntUnaryOperator
IntStream.of(1, 2, 3).map(i -> i * 2)
IntStream.of(1, 2, 3).map(i -> { return i * 2; })
// turn an IntStream to a Stream<Integer> with a
// Integer apply(int i) aka IntFunction<Integer>
IntStream.of(1, 2, 3).mapToObj(i -> i * 2)
IntStream.of(1, 2, 3).mapToObj(i -> { return i * 2; })
的所有内容都可以提供给Consumer<T>
的{{1}}流,该流可以是生成.map()
的任何形式的lambda表达式:
T
考虑到这一点,很容易看出void
表达式类型的lambda不能赋予.forEach(x -> System.out.println(x))
.forEach(x -> { System.out.println(x); }) // no return as you cannot return a void expression
.forEach(System.out::println) // shorter syntax for the same thing
.forEach(x -> { }) // just swallow the value
,并且不能给出非void
类型的lambda到.map()
。