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

Ben*_*Win 7 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);
Run Code Online (Sandbox Code Playgroud)

似乎第二个可以延伸到

Stream.of(1, 2, 3).map(i -> { return i * 2;}).forEach(System.out::println);
Run Code Online (Sandbox Code Playgroud)

它会编译好.我想出了这个,因为我已经习惯了第一个版本,但我的IDE(Netbeans)总是引用最后一个版本.

所以我的问题是:两种实现的区别/优势是什么?为什么带有{}块的那个需要返回值?需要该值的位置(编译代码除外)?

更新:

关于在Java 8 lambda语法中何时使用大括号?,这个不能仅仅因为关于lambda表达式语法

Stream.of(1, 2, 3).forEach(i -> { System.out.println(i); });
Run Code Online (Sandbox Code Playgroud)

编译好,所以必须(从我的下面)关于实现map().

干杯,本

glg*_*lgl 9

区别在于:

lambda表达式看起来像

parameters -> expression
Run Code Online (Sandbox Code Playgroud)

要么

parameters -> { block }
Run Code Online (Sandbox Code Playgroud)

其中,要么block返回一个值-或者它不是一个void样的行为.

换句话说,parameters -> expressionlambda等效于parameters -> { return expression; }if expression具有非void类型或者parameters -> { expression; }if expression具有void类型(例如System.out.printf()).

您的第一个版本实际上使用了一个带有一点开销的表达式:

i -> i = i * 2可以减少到i -> i * 2,因为i =赋值是不必要的,因为i之后立即消失而不再使用.

就像

Integer function(Integer i) {
    i = i * 2;
    return i;
}
Run Code Online (Sandbox Code Playgroud)

要么

Integer function(Integer i) {
    return (i = i * 2);
}
Run Code Online (Sandbox Code Playgroud)

这可以简化为

Integer function(Integer i) {
    return i * 2;
}
Run Code Online (Sandbox Code Playgroud)

所有这些示例都将匹配UnaryOperator<Integer>特殊情况的接口Function<Integer, Integer>.

相比之下,你的第二个例子是

XY function(int i) {
    i = i * 2;
}
Run Code Online (Sandbox Code Playgroud)

这不起作用:

  • 无论XYvoid(这将使一个Consumer<Integer>不与配合.map())
  • 或者XY确实Integer(然后缺少return语句).

需要该值的位置(编译代码除外)?

那么,.forEach(System.out::println);需要那个价值......

所以,一切都可以被转换成Function<T, R>可以提供给一个.map()一个的T流,从而导致一个在R流:

Stream.of(1, 2, 3).map(i -> i * 2)
Stream.of(1, 2, 3).map(i -> { return i * 2; })
Run Code Online (Sandbox Code Playgroud)

转向Integer你给另一个Integer,给你另一个Stream<Integer>.你注意到它们是盒装的吗?

其他方式

// 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; })
Run Code Online (Sandbox Code Playgroud)

所有这些示例的共同之处在于它们获得一个值并产生相同或不同类型的值.(注意这些示例如何根据需要使用AutoBoxing和AutoUnboxing.)

OTOH,可以转换为a的所有东西都Consumer<T>可以被赋予.map()一个T流,它可以是任何形式的lambda,它产生一个void表达式:

.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
Run Code Online (Sandbox Code Playgroud)

考虑到这一点,很容易看出void不能给出具有表达式类型的lambda,并且不能给出.map()具有非void类型的lambda forEach().

  • 好吧,即使没有终端`.forEach(System.out :: println)`,`map(...)`期望*Function*的事实足以要求lambda表达式返回一个值... (3认同)