0

I have some query regarding the performance enhancement using Stream API in java-08. Following is the code in java-06.

int sum = 0; for (int x : numbers) { sum += x; } 

This is the code in java-8.

 int sum = numbers.stream().reduce(0, (x,y) -> x+y); 

or:

int sum = numbers.stream().reduce(0, Integer::sum); 

Question :- though the number of lines in the both code is same but how the internal operation is going on ? That is how it is converting to stream and processing parallel.

5
  • See point Reduction operations in oracle doc docs.oracle.com/javase/8/docs/api/java/util/stream/… Commented Jul 14, 2017 at 10:47
  • 2
    that is way too broad... and probably many many good searches already contain your answer Commented Jul 14, 2017 at 11:14
  • 1
    @Eugene if you think you are bored in answer then please give some interesting solution. Commented Jul 14, 2017 at 11:27
  • 3
    it's not "boring", it's too broad. these are entirely different things Commented Jul 14, 2017 at 11:28
  • ok. Give me some links or doc reference where i can find my answer. I know it is little bored but for an architect this is challenging questions Commented Jul 14, 2017 at 11:35

2 Answers 2

4

First, your stream is not a parallel stream. you must call List#parallelStream or Stream#parallel explicitly. for example:

int sum = numbers.parallelStream().reduce(0, Integer::sum); 

A another way to summing the numbers is map a Stream<Integer> to a IntStream, it does unboxing N times but Stream#reduce does unboxing 2 *(N - 1) times and additional boxing operations if the stream size > 2, for example:

int sum = numbers.parallelStream().mapToInt(Integer::intValue).sum(); 

for the "how the internal operation is going on ?" , you can see the Eran's answer, he has described the parallel stream in detailed as far as I see.

Stream#reduce unboxing

the example of 1 + 2 + 3 + 4 + 5 reducing tree as below, the unboxing operation times: N = 10 ( 1(2) + 5(2) + 9(2) + 6(2) + 15(2)):

// v--- identity 0 1 2 3 4 5 1(2) 5(2) 9(2) 6(2) 9(/) 15(2) // ^ ^--- unboxing times, `/` means doesn't reducing at this time // | // |--- the sum result of current reducing 
Sign up to request clarification or add additional context in comments.

6 Comments

Stream reduce does uboxing 2 *(N - 1) times can you explain how ?
@HasnainAliBohra hi, the Eran's answer is already described that in the tree.
@HasnainAliBohra how about it now, sir?
@HasnainAliBohra :), Not at all.
Why 11(0)? Note that when you use reduce(0, Integer::sum), the variant with an identity element, the identity element will also combined with the other stream elements, so you have 2*N unboxing and N boxing operations—in the sequential case. For parallel reduction, every spawned subtask will use the identity element as starting point, so you’ll have even more boxing and unboxing going on.
|
1

There is no performance difference between .reduce(0, (x,y) -> x+y) and .reduce(0, Integer::sum). The differences are handled at compile time:

For the lambda expression, a synthetic method will be generated holding the lambda’s body, x+y. In contrast, Integer::sum refers to an existing method, which has exactly the same code. From that point, all that happens, will be the same. Your class will request the JRE to generate an implementation of the functional interface whose function method will invoke the specified method, the synthetic method or the existing one, both doing the same.

So in either case, you will end up with a JRE generated BinaryOperator which will invoke a method which returns the sum of both int arguments. Since there is no technical difference, there can’t be any performance difference.

But as holi-java correctly pointed out, both variants incorporate unnecessary boxing overhead. A BinaryOperator<Integer> receives two Integer instances, which is fine if both are existing ones, stemming from the collection, but will also return an Integer, which will be the boxed representation of the sum of the input. That sum might get passed into the next evaluation of the BinaryOperator<Integer>, being unboxed again.

In contrast,

int sum = numbers.stream().mapToInt(Integer::intValue).sum(); 

only has to unbox the objects from the collection, but will never box or unbox intermediate sums again. Note that you need a fairly large number of elements, before using parallelStream() instead of stream() will pay off.

7 Comments

How can you say that it is not unboxing at intermediate level. Is there is any oracle reference ??
@Hasnain Ali Bohra: mapToInt returns an IntStream. The whole type exists only to do the operations with primitive int values instead of objects.
@Holger first,up-vote. yeah, that is what I want to say. due to my bad english.... I say it simply.
so in that case there is no unboxing for IntStream while performing. As it is processing only with int. so the output from IntStream is int and if im assigning it to the Integer Then boxing will take place.
@Hasnain Ali Bohra: as said, the objects from the collection have to be unboxed, that’s unavoidable. This happens with mapToInt(Integer::intValue). Then, IntStream.sum() will sum up without any boxing or unboxing. In contrast, with Stream.reduce, every evaluation step has to return an object again, so (x,y)->x+y or Integer::sum will do the calculation with int, but then the result will be boxed to an Integer object.
|

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.