java 8中stream()。map()和stream.map({})之间的区别

时间:2015-04-17 10:08:52

标签: java java-8

昨天我偶然发现了一些我既不理解也无法找到解释的东西:

考虑以下操作:

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()的实现。

干杯,本

1 个答案:

答案 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

哪个不起作用:

  • voidConsumer<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()