Explain Codes LogoExplain Codes Logo

Java 8 stream reverse order

java
stream-engineering
performance
best-practices
Nikita BarsukovbyNikita Barsukov·Feb 25, 2025
TLDR

For an efficient reversal of a Stream in Java 8, use Comparator.reverseOrder() combined with sorted() on collections. Transform collections to streams, apply the reverse order, and collect:

List<String> reversed = List.of("a", "b", "c").stream() .sorted(Comparator.reverseOrder()) .collect(Collectors.toList());

This approach quickly inverts orders for Comparable elements. For integers or custom objects, be certain your Comparator fits:

List<Integer> reversedNums = List.of(1, 2, 3).stream() .sorted(Comparator.reverseOrder()) .collect(Collectors.toList());

This nifty method turns your lists or sets upside down with minimal fuss.

Efficient alternatives for stream reversal

Box-free IntStream reversal

Avoid boxing Integers. Use a revRange method for reversing an IntStream:

IntStream revRange(int from, int to) { return IntStream.iterate(to - 1, i -> i >= from, i -> i - 1); }

This produces an IntStream from to-1 to from and creates great savings via avoiding the boxing cost. Magic!

Stream reversal with ArrayDeque

Remember ArrayDeque—it's far more efficient when dealing with non-primitive streams. Use Collectors.toCollection for a streamlined reverse:

ArrayDeque<String> reversedQueue = stream.collect(Collectors.toCollection(ArrayDeque::new)); // And voila! Convert it back to a Stream Stream<String> reversedStream = reversedQueue.descendingIterator().asIterator();

Unlike ArrayList, ArrayDeque gives us a performance edge for front-ended insertions. Efficiency for the win!

Custom collectors for the power users

Go the extra mile with a custom collector:

Collector<T, ?, Deque<T>> toReversedDeque() { return Collector.of( ArrayDeque::new, Deque::addFirst, (d1, d2) -> { d2.forEach(d1::addFirst); return d1; }, Collector.Characteristics.IDENTITY_FINISH ); }

Insert elements directly at the front of a deque, reversing the stream with flair.

Caution and peculiarities while reversing streams

Keep an eye on unordered streams and parallelism

When dealing with unordered streams, pause for thought. Stream reversal might not make semantic sense. Evaluate how reversal techniques influence performance on parallel streams.

Number ranges - flip them with style!

This bit of code flips a numerical range:

IntStream.range(from, to).map(i -> to - i + from - 1);

Stuart Marks's pattern—excellent at managing potential integer overflows. Kudos, Stuart!

A word on custom sorting - handle with care!

Custom sort functions such as .sorted((a, b) -> -1) can create black holes in your sorter's contract, causing undefined behavior. Stick with tried-and-true practices like Collections.reverseOrder() for a smooth ride.

Tips and tricks for different stream sources

Reversing arrays - it's not rocket science!

For arrays, collect elements in temporary storage and go back in time (literally):

Object[] elements = stream.toArray(); Stream<?> reversedStream = IntStream.range(0, elements.length) .mapToObj(i -> elements[elements.length - i - 1]);

This allows easy-peasy lemon-squeezy stream reversal without boxing overhead.

Parallel streams and sorting - a deadly combo!

Using .sorted(Collections.reverseOrder()) for reversing parallel streams—tempting but risky. Could lead to deadlocks or resource drains. Choose wisely, young Jedi.

Reversal without intermediate storage - wishful thinking!

Spoiler alert: You cannot reverse a stream on-the-fly, gotta gather those elements first. The stream abstraction in Java doesn't support backflips—a decision made for forward compatibility.