The difference between stream (). Map () and stream.map ({}) in java 8

Yesterday I came across something that I really don't understand, and I can't 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 seems that the second can continue to

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

and it will just compile. I came up with this because I'm used to the first version, but my IDE (Netbeans) always refers to the latest version.

So my question is: what is the difference / advantage of these two implementations? And why does a block with a block {} require a return value? Where is this value needed (except that the code is compiled)?

Update:

Regarding When braces are optional in Java 8 lambda syntax? it can't be about lambda syntax syntax just because

 Stream.of(1, 2, 3).forEach(i -> { System.out.println(i); }); 

compiles fine, so there should be (from my understanding) about map() implementation.

Cheers, Ben

+7
java java-8
source share
1 answer

The difference is as follows:

Lambda expression looks like

 parameters -> expression 

or

 parameters -> { block } 

where either block returns a value - or it is not suitable for void behavior.

In other words, a parameters -> expression lambda is equivalent to parameters -> { return expression; } parameters -> { return expression; } if expression has a non-empty type or parameters -> { expression; } parameters -> { expression; } if expression is of type void (for example, System.out.printf() ).

Your first version essentially uses an expression with a bit of overhead:

i -> i = i * 2 can be reduced to i -> i * 2 , since the purpose of i = simply not necessary, because i immediately disappears without being used further.

It looks 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 correspond to the UnaryOperator<Integer> interface, which is a special case of Function<Integer, Integer> .

On the contrary, you second example is similar to

 XY function(int i) { i = i * 2; } 

which does not work:

  • Or XY is void (which would make a Consumer<Integer> that doesn't match .map() )
  • Or XY really Integer (then the return statement is missing).

Where is the need for this value (except that the code is compiled)?

Well, .forEach(System.out::println); needs this value ...

So, everything that can be converted to Function<T, R> can be transferred to the stream .map() stream T , resulting in stream R :

 Stream.of(1, 2, 3).map(i -> i * 2) Stream.of(1, 2, 3).map(i -> { return i * 2; }) 

rotate the Integer , which you pass into another Integer , giving you another Stream<Integer> . Did you notice that they are in the box?

Other methods:

 // 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 of these examples have a common meaning that they receive a value and produce a value of one or another type. (Note how these examples use AutoBoxing and AutoUnboxing as needed.)

OTOH, everything that can be converted to Consumer<T> can be passed to the .map() stream of stream T , which can be any form of lambda that expresses the 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 this in mind, it is easy to see that lambda with the void expression type cannot be assigned to .map() , and lambda with the void type cannot be assigned to forEach() .

+9
source share

All Articles