If I have multiple operations being performed on stream, how are they computed internally.
List<Integer> ee = new ArrayList<Integer>();
Function<? super Integer, ? extends Integer> f1 = x -> x * 2;
Function<? super Integer, ? extends Integer> f2 = x -> x * x;
Function<? super Integer, ? extends Integer> f3 = x -> x / 2;
ee.stream().map(f1.compose(f2.andThen(f3))).collect(Collectors.toList());
ee.stream().map(f1).map(f2).map(f3).collect(Collectors.toList());
Editin the question to add multiple map operations. How are map functions computed in case of multiple map function application. When talking about non-parallel stream, is the order of computation of elements depends only on the type of input collection (i,e ordered for list, linkedHashmap , sortedset and unordered for hashSet, etc). Also, Can I get some more insights on the internal working of streams so as to decide better on when are streams not advised to use and when are they advised to be used most.(collection size, nature of sequence, etc, )
- Is it computed in the same sequence as that of the input collection?
Not necessariliy. There are many things that can determine order. On the stream itself, there is unordered() and parallel() which affect it. Then, you can also influence it with the terminal operation, for example forEach vs forEachOrdered(). For collect, it depends on the underlying Collection you are collecting into. For toList(), it collects them in the order your stream is currently serving. So if you did not call unordered() or anything, it will be ordered.
From the official documentation:
Returns a Collector which collects all the input elements into a List, in encounter order.
- Does it apply function to all the elements and then moves to evaluate the next function ? or it applies all functions on one element , then second element ... so on.
As long as you do not apply a terminal operation, such as collect, nothing happens. It memorizes your actions and creates an action-pipe. As soon as you start, by having collect, it will iterate all items one after another and apply the full action-pipe to it. So it will take one single element and apply all your functions to it, then stuff it into the resulting list and after that move on to the next element.
However, in your specific case, you only have one single map(...) operation. So instead of telling the stream to apply 3 functions, you used the methods in function to compose the 3 functions into one big-function and gave that single function to the stream. So the stream only has one function to work with, which does all your 3 operations one after another, when applied. Usually people go for using multiple map(...) calls:
ee.stream()
.map(f1)
.map(f2)
.map(f3)
.collect(Collectors.toList());
- How is it any different from normal iterations performed on collection in respect of performance.
In general, there is more logic attached to streams. You need to construct some objects, Create some action-pipelines etc. So it introduces a bit of overhead, nothing serious though. So as long as you do not have tiny mini data sets and you need every nanosecond, consider it equally good to ordinary iteration.
There are a couple of advantages though. One can be readability (not always of course). And the other prominent advantage is that the Stream API offers multi-threading for free. You just call parallel() to suggest the usage and if Java thinks this is a good idea, it will start processing multiple elements at the same time.
Bear in mind though that multi-threading comes with a significant overhead. So if your data source is not big, it might be slower in total.
- Is it computed in the same sequence as that of the input collection?
Yes, because the Spliterator returned by an ArrayList is ordered:
ee.stream().spliterator().hasCharacteristics(Spliterator.ORDERED); // prints true
- Does it apply function to all the elements and then moves to evaluate the next function ? Or it applies all functions on one element, then second element ... so on.
The second one. The Stream doesn't know anything about the internal structure of the mapping function, so it treats it as a single (indivisible) function.
- How is it any different from normal iterations performed on collection in respect of performance.
This was asked many times on StackOverflow. Generally, Streams are a bit slower than their loop counterparts.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With