0

Can you explain the execution process of the below code? mainly the sorted method.

Stream.of("d2", "a2", "b1", "b3", "c")
    .sorted((s1, s2) -> {
        System.out.printf("sort: %s; %s\n", s1, s2);
        return s1.compareTo(s2);
    })
    .filter(s -> {
        System.out.println("filter: " + s);
        return s.startsWith("a");
    })
    .map(s -> {
        System.out.println("map: " + s);
        return s.toUpperCase();
    })
    .forEach(s -> System.out.println("forEach: " + s));

Output:

sort:    a2; d2
sort:    b1; a2
sort:    b1; d2
sort:    b1; a2
sort:    b3; b1
sort:    b3; d2
sort:    c; b3
sort:    c; d2
filter:  a2
map:     a2
forEach: A2
filter:  b1
filter:  b3
filter:  c
filter:  d2

Thanks, Ref: https://winterbe.com/posts/2014/07/31/java8-stream-tutorial-examples/

Ousmane D.
  • 54,915
  • 8
  • 91
  • 126
X_code_X
  • 11
  • 1

2 Answers2

1

So Java8 tries to speed up execution by doing all of the higher-order functions as soon as possible for any given input. That is, for example, if you call map twice in a row on a list then it will access each element of the list only one time. This speeds it up because it goes from 2 passes through the list to one. To illustrate, take this simple example:

Stream.of(1, 2, 3)
    .map(s -> {
        System.out.println("map: " + s.toString());
        return s;
    })
    .map(s -> {
        System.out.println("map: " + s.toString());
        return s;
    })

This will print:

1
1
2
2
3
3

Because it is faster to 'touch' each element in the list one time than it is to iterate through the list fully for both maps!

In terms of your example, let's take it piece by piece:

sort:    a2; d2
sort:    b1; a2
sort:    b1; d2
sort:    b1; a2
sort:    b3; b1
sort:    b3; d2
sort:    c; b3
sort:    c; d2

All of the sorting needs to happen at the same time, and it all needs to happen first. This is because the computer cannot know which element will be in which spot until the sorting is done (i.e. it can't do map on the same list location twice, because sort may change that)

Next, you essentially have this:

Stream.of("a2", "b1", "b3", "c", "d2")
    .filter(s -> {
        System.out.println("filter: " + s);
        return s.startsWith("a");
     })
    .map(s -> {
        System.out.println("map: " + s);
        return s.toUpperCase();
    })
    .forEach(s -> System.out.println("forEach: " + s));

Now, to minimize passes throught he list, Java will go through each element in the list and execute the filter and then the map and then the forEach. This is because none of these depend on the positions of the elements. In other words, Java sees that it can do all of these actions on each element, rather than by iterating through the whole list three time, for each function!

Now:

filter:  a2
map:     a2
forEach: A2

We filter the first element, then we map over it, then we do the final forEach print.

filter:  b1
filter:  b3
filter:  c
filter:  d2

These all get filtered out, so the rest of the functions don't get called!

K. Dackow
  • 456
  • 1
  • 3
  • 15
0

You seem to be confused about why there are several sorted calls consecutively in your output.

Let's explain this; firstly, intermediate operations are divided into either stateless as such of filter, map et al and stateful e.g. sorted, distinct et al

As mentioned by Brian Goetz here under Executing a stream pipeline:

A stateless operation is one that can be performed on an element without knowledge of any of the other elements. For example, a filtering operation only needs to examine the current element to determine whether to include or eliminate it, but a sorting operation must see all the elements before it knows which element to emit first.

Emphasis mine.

The fact that a sorting operation must see all the elements before emitting a given element to the next operation is the reason why you're seeing several sorted calls consecutively in your output.


Further, you may also want to read are Java streams stages sequential? which derives about the sorted operation to some extent.

Ousmane D.
  • 54,915
  • 8
  • 91
  • 126