What is the difference between Stream.of and IntStream.range?

JavaJava Stream

Java Problem Overview


Please, consider this code:

System.out.println("#1");
Stream.of(0, 1, 2, 3)
        .peek(e -> System.out.println(e))
        .sorted()
        .findFirst();

System.out.println("\n#2");
IntStream.range(0, 4)
        .peek(e -> System.out.println(e))
        .sorted()
        .findFirst();

The output will be:

#1
0
1
2
3

#2
0

Could anyone explain, why output of two streams are different?

Java Solutions


Solution 1 - Java

Well, IntStream.range() returns a sequential ordered IntStream from startInclusive(inclusive) to endExclusive (exclusive) by an incremental step of 1, which means it's already sorted. Since it's already sorted, it makes sense that the following .sorted() intermediate operation does nothing. As a result, peek() is executed on just the first element (since the terminal operation only requires the first element).

On the other hand, the elements passed to Stream.of() are not necessarily sorted (and the of() method doesn't check if they are sorted). Therefore, .sorted() must traverse all the elements in order to produce a sorted stream, which allows the findFirst() terminal operation to return the first element of the sorted stream. As a result, peek is executed on all the elements, even though the terminal operation only needs the first element.

Solution 2 - Java

IntStream.range is already sorted:

// reports true
System.out.println(
       IntStream.range(0, 4)
                .spliterator()
                .hasCharacteristics(Spliterator.SORTED)
);

So when sorted() method on the Stream is hit, internally, it will become a NO-OP.

Otherwise, as you already see in your first example, all the elements have to be sorted, only then findFirst can tell who is "really the first one".

Just notice that this optimization only works for naturally sorted streams. For example:

// prints too much you say?
Stream.of(new User(30), new User(25), new User(34))
			.peek(x -> System.out.println("1 : before I call first sorted"))
			.sorted(Comparator.comparing(User::age))
			.peek(x -> System.out.println("2 : before I call second sorted"))
			.sorted(Comparator.comparing(User::age))
			.findFirst();

where (for brevity):

record User(int age) { }

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionPavel_KView Question on Stackoverflow
Solution 1 - JavaEranView Answer on Stackoverflow
Solution 2 - JavaEugeneView Answer on Stackoverflow