问题
Yesterday i stumbled over something i neither really understand nor i'm able to find an explanation:
Consider the following operations:
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);
It appears that the second one can be extended to
Stream.of(1, 2, 3).map(i -> { return i * 2;}).forEach(System.out::println);
and it will just compile fine. I came up with this because i'm kinda used to the first version but my IDE (Netbeans) always refers to the last version.
So my Question is: What is the difference/advantage of these two implementations? And why does the one with the {} block requires a return value? Where is the need for that value (except to make the code compile)?
Update:
With respect to When are braces optional in Java 8 lambda syntax?, this one can't be about lambda expression syntax only because
Stream.of(1, 2, 3).forEach(i -> { System.out.println(i); });
compiles fine, so is has to be(from my understading) about the implementation of map().
Cheers, Ben
回答1:
The difference is the following:
A lambda expression looks like
parameters -> expression
or
parameters -> { block }
where either the block returns a value - or it doesn't for a void-like behaviour.
In other words, a parameters -> expression lambda is equivalent to parameters -> { return expression; } if expression has a non-void type or to parameters -> { expression; } if expression has void type (such as System.out.printf()).
Your first version essentially uses an expression with a bit of overhead:
i -> i = i * 2 could be reduced to i -> i * 2, as the i = assignment is just unnecessary, because i disappears immediately afterwards without being used any further.
It is just like
Integer function(Integer i) {
i = i * 2;
return i;
}
or
Integer function(Integer i) {
return (i = i * 2);
}
which can be simplified to
Integer function(Integer i) {
return i * 2;
}
All these examples would match the interface UnaryOperator<Integer> which is a special case for Function<Integer, Integer>.
In contrast, you 2nd example is like
XY function(int i) {
i = i * 2;
}
which doesn't work:
- Either
XYisvoid(which would make aConsumer<Integer>which doesn't fit with.map()) - Or
XYis indeedInteger(then the return statement is missing).
Where is the need for that value (except to make the code compile)?
Well, .forEach(System.out::println); needs that value...
So, everything which can be converted to a Function<T, R> can be given to a .map() of a T stream, resulting in an R stream:
Stream.of(1, 2, 3).map(i -> i * 2)
Stream.of(1, 2, 3).map(i -> { return i * 2; })
turn the Integer you give into another Integer, giving you another Stream<Integer>. You notice that they are boxed?
Other ways would be
// 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; })
All these examples have in common that they get a value and produce a value of either the same or a different type. (Note how these examples use AutoBoxing and AutoUnboxing as needed.)
OTOH, everything which can be converted to a Consumer<T> can be given to a .map() of a T stream, which can be any form of lambda which produces a void expression:
.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
With that in mind, it is easy to see that a lambda with void expression type cannot be given to .map(), and a lambda with a non-void type cannot be given to forEach().
来源:https://stackoverflow.com/questions/29696283/difference-between-stream-map-and-stream-map-in-java-8