243

General question: What's the proper way to reverse a stream? Assuming that we don't know what type of elements that stream consists of, what's the generic way to reverse any stream?

Specific question:

IntStream provides range method to generate Integers in specific range IntStream.range(-range, 0), now that I want to reverse it switching range from 0 to negative won't work, also I can't use Integer::compare

List<Integer> list = Arrays.asList(1,2,3,4); list.stream().sorted(Integer::compare).forEach(System.out::println); 

with IntStream I'll get this compiler error

Error:(191, 0) ajc: The method sorted() in the type IntStream is not applicable for the arguments (Integer::compare)

what am I missing here?

11
  • 2
    An IntStream has no .sorted(Comparator) method; you have to go through a Stream<Integer> first and reverse there before yielding an IntStream Commented Jun 3, 2014 at 8:23
  • 7
    To generate an IntStream.range(0, n) in reverse order, do something like map(i -> n - i - 1). No need to do boxing and sorting. Commented Jun 3, 2014 at 8:39
  • 4
    Your gerneral question and your specific question read like two completele different questions to me. The general speaks of reversing the stream, while the specific speaks of ordering numbers in descending order. If the stream produces the numbers in an unordered manner like 1, 3, 2, what is your expected outcome? Do you want the reversed stream like 2, 3, 1 or the sorted stream like 3, 2, 1? Commented Jun 3, 2014 at 8:54
  • 13
    You can't reverse a stream in general - for example a stream may be inifinite. Commented Jun 3, 2014 at 9:01
  • 1
    You may want to rephrase the question as "Iterate a collection in reverse order in Java 8 way". Answer may be beyond streams. Below answer from @venkata-raju solves the problem, but takes extra space. I'm still waiting to see a good answer on this question. Commented Dec 10, 2015 at 12:56

33 Answers 33

116

For the specific question of generating a reverse IntStream, try something like this:

static IntStream revRange(int from, int to) { return IntStream.range(from, to) .map(i -> to - i + from - 1); } 

This avoids boxing and sorting.

For the general question of how to reverse a stream of any type, I don't know of there's a "proper" way. There are a couple ways I can think of. Both end up storing the stream elements. I don't know of a way to reverse a stream without storing the elements.

This first way stores the elements into an array and reads them out to a stream in reverse order. Note that since we don't know the runtime type of the stream elements, we can't type the array properly, requiring an unchecked cast.

@SuppressWarnings("unchecked") static <T> Stream<T> reverse(Stream<T> input) { Object[] temp = input.toArray(); return (Stream<T>) IntStream.range(0, temp.length) .mapToObj(i -> temp[temp.length - i - 1]); } 

Another technique uses collectors to accumulate the items into a reversed list. This does lots of insertions at the front of ArrayList objects, so there's lots of copying going on.

Stream<T> input = ... ; List<T> output = input.collect(ArrayList::new, (list, e) -> list.add(0, e), (list1, list2) -> list1.addAll(0, list2)); 

It's probably possible to write a much more efficient reversing collector using some kind of customized data structure.

UPDATE 2016-01-29

Since this question has gotten a bit of attention recently, I figure I should update my answer to solve the problem with inserting at the front of ArrayList. This will be horribly inefficient with a large number of elements, requiring O(N^2) copying.

It's preferable to use an ArrayDeque instead, which efficiently supports insertion at the front. A small wrinkle is that we can't use the three-arg form of Stream.collect(); it requires the contents of the second arg be merged into the first arg, and there's no "add-all-at-front" bulk operation on Deque. Instead, we use addAll() to append the contents of the first arg to the end of the second, and then we return the second. This requires using the Collector.of() factory method.

The complete code is this:

Deque<String> output = input.collect(Collector.of( ArrayDeque::new, (deq, t) -> deq.addFirst(t), (d1, d2) -> { d2.addAll(d1); return d2; })); 

The result is a Deque instead of a List, but that shouldn't be much of an issue, as it can easily be iterated or streamed in the now-reversed order.

Sign up to request clarification or add additional context in comments.

4 Comments

Alternatively: IntStream.iterate(to-1, i->i-1).limit(to-from)
@Holger Unfortunately, that solution doesn't handle overflow correctly.
@Brandon Mintern: indeed, you would have to use .limit(endExcl-(long)startIncl) instead, but for such large streams, it is very discouraged anyway as it’s much less efficient than the range based solution. At the time I wrote the comment, I wasn’t aware about the efficiency difference.
Or IntStream.rangeClosed(1, to - from).map(i -> to-i) (see bjmi's comment, too).
75

Elegant solution

List<Integer> list = Arrays.asList(1,2,3,4); list.stream() .sorted(Collections.reverseOrder()) // Method on Stream<Integer> .forEach(System.out::println); 

4 Comments

It is elegant but not fully working as it seems as elements of the list are required to be Comparable...
That's assuming we want elements to be sorted in reverse order. The question is about reversing the order of a stream.
@KrzysztofWolny you can pass a comparator function to reverseOrder(), so that shouldn't be too much of a bother
i think we are missing the point of the question, the stream api is normally backed by finite source (an array/list whatever), its not like a hot observable stream. The purpose was to do this efficiently like you would write a for loop iterating down instead of up... which i think is possible with custom spliterator.
63

General Question:

Stream does not store any elements.

So iterating elements in the reverse order is not possible without storing the elements in some intermediate collection.

Stream.of("1", "2", "20", "3") .collect(Collectors.toCollection(ArrayDeque::new)) // or LinkedList .descendingIterator() .forEachRemaining(System.out::println); 

Update: Changed LinkedList to ArrayDeque (better) see here for details

Prints:

3 20 2 1 

By the way, using sort method is not correct as it sorts, NOT reverses (assuming stream may have unordered elements)

Specific Question:

I found this simple, easier and intuitive(Copied @Holger comment)

IntStream.iterate(to - 1, i -> i - 1).limit(to - from) 

5 Comments

Some stream operation, such as sorted and distinct actually store an intermediate result. See the package API docs for some information about that.
@Lii I see No storage in the same page. Even it stores we can't get access to that storage (so No storage is fine i guess)
Good answer. But since extra space is used, it many not be a great idea for programmers to use your approach on very large collection.
I like the simplicity of the solution from an understandability perspective and leveraging an existing method on an existing data structure...the solution previous with a map implementation is harder to understand but for sure Manu is right, for large collections I would not use this intuitive, and would opt for the map one above.
This is one of the few correct answers here. Most of the other ones don't actually reverse the stream, they try to avoid doing it somehow (which only works under peculiar sets of circumstances under which you normally wouldn't need to reverse in the first place). If you try to reverse a stream that doesn't fit into memory you're doing it wrong anyway. Dump it into a DB and get a reversed stream using regular SQL.
48

The easiest way to do it properly:

List<Integer> list = Arrays.asList(1, 4, 2, 5, 3); Collections.reverse(list); System.out.println(list); 

Output:
[3, 5, 2, 4, 1]

The same for String:

List<String> stringList = Arrays.asList("A", "D", "B", "E", "C"); Collections.reverse(stringList); System.out.println(stringList); 

Output:
[C, E, B, D, A]

How NOT to do it:

  • Don't use .sorted(Comparator.reverseOrder()) or .sorted(Collections.reverseOrder()), because it will just sort elements in the descending order.
    Using it for given Integer input:
    [1, 4, 2, 5, 3]
    the output would be as follows:
    [5, 4, 3, 2, 1]
    For String input:
    ["A", "D", "B", "E", "C"]
    the output would be as follows:
    [E, D, C, B, A]
  • Don't use .sorted((a, b) -> -1) (explanation below)

Don't use .sorted((a, b) -> -1)!
It breaks comparator contract and might work only for some cases ie. only on single thread but not in parallel.
yankee explanation:

(a, b) -> -1 breaks the contract for Comparator. Whether this works depends on the implementation of the sort algorithm. The next release of the JVM might break this. Actually I can already break this reproduciblly on my machine using IntStream.range(0, 10000).parallel().boxed().sorted((a, b) -> -1).forEachOrdered(System.out::println);

//Don't use this!!! List<Integer> list = Arrays.asList(1, 4, 2, 5, 3); List<Integer> reversedList = list.stream() .sorted((a, b) -> -1) .collect(Collectors.toList()); System.out.println(reversedList); 

Output in positive case:
[3, 5, 2, 4, 1]

Possible output in parallel stream or with other JVM implementation:
[4, 1, 2, 3, 5]

The same for String:

//Don't use this!!! List<String> stringList = Arrays.asList("A", "D", "B", "E", "C"); List<String> reversedStringList = stringList.stream() .sorted((a, b) -> -1) .collect(Collectors.toList()); System.out.println(reversedStringList); 

Output in positive case:
[C, E, B, D, A]

Possible output in parallel stream or with other JVM implementation:
[A, E, B, D, C]

3 Comments

(a, b) -> -1 breaks the contract for Comparator. Whether this works depends on the implementation of the sort algorithm. The next release of the JVM might break this. Actually I can already break this reproduciblly on my machine using IntStream.range(0, 10000).parallel().boxed().sorted((a, b) -> -1).forEachOrdered(System.out::println);
@yankee Yes you are right. It breaks Comparator contract and is kind of misuse of Comparator. It works fine for single thread, but even if you don't use .parallel() you can't rely on it, because you don't know how virtual machine will run this and you don't know which sorting algorithm will be used (maybe even sorting algorithm working on single thread might break with this implementation). Thank you for your comment. I will revise my answer in my free time.
I revised my answer according to yankee comment. Now the answer should be correct.
43

Many of the solutions here sort or reverse the IntStream, but that unnecessarily requires intermediate storage. Stuart Marks's solution is the way to go:

static IntStream revRange(int from, int to) { return IntStream.range(from, to).map(i -> to - i + from - 1); } 

It correctly handles overflow as well, passing this test:

@Test public void testRevRange() { assertArrayEquals(revRange(0, 5).toArray(), new int[]{4, 3, 2, 1, 0}); assertArrayEquals(revRange(-5, 0).toArray(), new int[]{-1, -2, -3, -4, -5}); assertArrayEquals(revRange(1, 4).toArray(), new int[]{3, 2, 1}); assertArrayEquals(revRange(0, 0).toArray(), new int[0]); assertArrayEquals(revRange(0, -1).toArray(), new int[0]); assertArrayEquals(revRange(MIN_VALUE, MIN_VALUE).toArray(), new int[0]); assertArrayEquals(revRange(MAX_VALUE, MAX_VALUE).toArray(), new int[0]); assertArrayEquals(revRange(MIN_VALUE, MIN_VALUE + 1).toArray(), new int[]{MIN_VALUE}); assertArrayEquals(revRange(MAX_VALUE - 1, MAX_VALUE).toArray(), new int[]{MAX_VALUE - 1}); } 

9 Comments

awesome and simple. Is this from some opensource utilty? (the Estreams thing) or some piece of your code?
Thanks! Unfortunately, I didn't intend to leak the Estreams name (I'm going to remove it from the post). It's one of our company's internal utility classes, which we use to supplement java.util.stream.Stream's static methods.
Okay…“awesome and simple”… Is there any case that this solution handles, which Stuart Marks’ even simpler solution didn’t already handle more than one and a half year ago?
I just tested his solution with my test method above; it passes. I was unnecessarily avoiding overflow instead of embracing it as he did. I agree that his is better. I'll edit mine to reflect that.
@vach, you may use by StreamEx specifying step: IntStreamEx.rangeClosed(from-1, to, -1)
|
21

without external lib... (TL;DR: skip to the last method)

import java.util.List; import java.util.ArrayList; import java.util.Collections; import java.util.stream.Collector; import java.util.stream.Collectors; public class MyCollectors { // assuming Collectors.toList() returns mutable list public static <T> Collector<T, ?, List<T>> toListReversed() { return Collectors.collectingAndThen( Collectors.toList(), l -> { Collections.reverse(l); return l; } ); } // EDIT: // Thx to the suggestion from @M.Justin: // because Collectors.toList() does not guarantee to give us // a mutable/reversable ArrayList, we might come up with this... // though this will not support collecting from parallel streams. public static <T> Collector<T, ?, ArrayList<T>> toListReversed() { return Collectors.collectingAndThen( Collections.toCollection(ArrayList::new), l -> { Collections.reverse(l); return l; } ); } // I also like the answer from @lexicalscope, // but without external libs. // Compared to both implementations from above: // - No wrapper around ArrayList::new. // - It has a combiner for parallel streams. public static <T> Collector<T, ?, ArrayList<T>> toListReversed() { return Collector.<T, ArrayList<T>, ArrayList<T>>of( ArrayList::new, (l, x) -> l.add(x), (l1, l2) -> { l1.addAll(l2); return l1; }, l -> { Collections.reverse(l); return l; } ); } } 

2 Comments

Collectors.toList() explicitly does not guarantee that the resulting list will be mutable, which is something that Collections.reverse requires in order to change the list. "There are no guarantees on the […] mutability […] of the List returned; if more control over the returned List is required, use toCollection(Supplier)." Collections.toCollection(ArrayList::new) would be guaranteed to work, whereas toList just happens to work given current implementations of the Java libraries.
Thx, @M.Justin. I will apply the change. I also like the answer stackoverflow.com/a/24717422
14

You could define your own collector that collects the elements in reverse order:

public static <T> Collector<T, List<T>, List<T>> inReverse() { return Collector.of( ArrayList::new, (l, t) -> l.add(t), (l, r) -> {l.addAll(r); return l;}, Lists::<T>reverse); } 

And use it like:

stream.collect(inReverse()).forEach(t -> ...) 

I use an ArrayList in forward order to efficiently insert collect the items (at the end of the list), and Guava Lists.reverse to efficiently give a reversed view of the list without making another copy of it.

Here are some test cases for the custom collector:

import static org.hamcrest.MatcherAssert.assertThat; import static org.hamcrest.Matchers.*; import java.util.ArrayList; import java.util.List; import java.util.function.BiConsumer; import java.util.function.BinaryOperator; import java.util.function.Function; import java.util.function.Supplier; import java.util.stream.Collector; import org.hamcrest.Matchers; import org.junit.Test; import com.google.common.collect.Lists; public class TestReverseCollector { private final Object t1 = new Object(); private final Object t2 = new Object(); private final Object t3 = new Object(); private final Object t4 = new Object(); private final Collector<Object, List<Object>, List<Object>> inReverse = inReverse(); private final Supplier<List<Object>> supplier = inReverse.supplier(); private final BiConsumer<List<Object>, Object> accumulator = inReverse.accumulator(); private final Function<List<Object>, List<Object>> finisher = inReverse.finisher(); private final BinaryOperator<List<Object>> combiner = inReverse.combiner(); @Test public void associative() { final List<Object> a1 = supplier.get(); accumulator.accept(a1, t1); accumulator.accept(a1, t2); final List<Object> r1 = finisher.apply(a1); final List<Object> a2 = supplier.get(); accumulator.accept(a2, t1); final List<Object> a3 = supplier.get(); accumulator.accept(a3, t2); final List<Object> r2 = finisher.apply(combiner.apply(a2, a3)); assertThat(r1, Matchers.equalTo(r2)); } @Test public void identity() { final List<Object> a1 = supplier.get(); accumulator.accept(a1, t1); accumulator.accept(a1, t2); final List<Object> r1 = finisher.apply(a1); final List<Object> a2 = supplier.get(); accumulator.accept(a2, t1); accumulator.accept(a2, t2); final List<Object> r2 = finisher.apply(combiner.apply(a2, supplier.get())); assertThat(r1, equalTo(r2)); } @Test public void reversing() throws Exception { final List<Object> a2 = supplier.get(); accumulator.accept(a2, t1); accumulator.accept(a2, t2); final List<Object> a3 = supplier.get(); accumulator.accept(a3, t3); accumulator.accept(a3, t4); final List<Object> r2 = finisher.apply(combiner.apply(a2, a3)); assertThat(r2, contains(t4, t3, t2, t1)); } public static <T> Collector<T, List<T>, List<T>> inReverse() { return Collector.of( ArrayList::new, (l, t) -> l.add(t), (l, r) -> {l.addAll(r); return l;}, Lists::<T>reverse); } } 

1 Comment

As of Java 21, the Guava method Lists::reverse static method can be replaced with the JDK instance method List::reversed.
10

If implemented Comparable<T> (ex. Integer, String, Date), you can do it using Comparator.reverseOrder().

List<Integer> list = Arrays.asList(1, 2, 3, 4); list.stream() .sorted(Comparator.reverseOrder()) .forEach(System.out::println); 

1 Comment

This doesn't reverse the stream. It sorts the stream in reverse order. So if you had Stream.of(1,3,2) the result would be Stream.of(3,2,1) NOT Stream.of(2,3,1)
9

cyclops-react StreamUtils has a reverse Stream method (javadoc).

 StreamUtils.reverse(Stream.of("1", "2", "20", "3")) .forEach(System.out::println); 

It works by collecting to an ArrayList and then making use of the ListIterator class which can iterate in either direction, to iterate backwards over the list.

If you already have a List, it will be more efficient

 StreamUtils.reversedStream(Arrays.asList("1", "2", "20", "3")) .forEach(System.out::println); 

2 Comments

Nice didnt know about this project
cyclops now also comes with Spliterators for efficient Stream reversal (currently for Ranges, arrays and Lists). Creating cyclops SequenceM Stream extension with SequenceM.of, SequenceM.range or SequenceM.fromList will automatically take advantage of efficiently reversible spliterators.
7

Here's the solution I've come up with:

private static final Comparator<Integer> BY_ASCENDING_ORDER = Integer::compare; private static final Comparator<Integer> BY_DESCENDING_ORDER = BY_ASCENDING_ORDER.reversed(); 

then using those comparators:

IntStream.range(-range, 0).boxed().sorted(BY_DESCENDING_ORDER).forEach(// etc... 

8 Comments

This is only an answer to your "specific question" but not to your "general question".
Collections.reverseOrder() exists since Java 1.2 and works with Integer
@M.Justin and maybe even newer Java versions will introduce even more alternatives. So what’s the point? My point was that there’s a working built-in solution since 1998 which wasn’t “too new to know it” even back in 2014…
@M.Justin well, that was my point too, except that I highlighted that even 16 years before that answer there was a better alternative. The release of Java 8 did not invalidate that old solution. Since this had been said already a decade ago, I don’t see what your mentioning of newer methods adds to it.
@M.Justin that’s fair, but in this case, the use of Integer::compare only serves to have something to call reversed() on. If you want natural order, you could simply call sorted() without a comparator (if range wasn’t already in natural order anyway). So sorted(Collections.reverseOrder()) obsoletes the entire answer. But you’re right, if you ever need an explicit comparator expressing the natural order, Comparator.naturalOrder() is the way to go. But this information should not be buried under a decade old answer…
|
7

I would suggest using jOOλ, it's a great library that adds lots of useful functionality to Java 8 streams and lambdas.

You can then do the following:

List<Integer> list = Arrays.asList(1,2,3,4); Seq.seq(list).reverse().forEach(System.out::println) 

Simple as that. It's a pretty lightweight library, and well worth adding to any Java 8 project.

Comments

7

With regard to the specific question of generating a reverse IntStream:

starting from Java 9 you can use the three-argument version of the IntStream.iterate(...):

IntStream.iterate(10, x -> x >= 0, x -> x - 1).forEach(System.out::println); // Out: 10 9 8 7 6 5 4 3 2 1 0 

where:

IntStream.iterate​(int seed, IntPredicate hasNext, IntUnaryOperator next);

  • seed - the initial element;
  • hasNext - a predicate to apply to elements to determine when the stream must terminate;
  • next - a function to be applied to the previous element to produce a new element.

Comments

5

How about this utility method?

public static <T> Stream<T> getReverseStream(List<T> list) { final ListIterator<T> listIt = list.listIterator(list.size()); final Iterator<T> reverseIterator = new Iterator<T>() { @Override public boolean hasNext() { return listIt.hasPrevious(); } @Override public T next() { return listIt.previous(); } }; return StreamSupport.stream(Spliterators.spliteratorUnknownSize( reverseIterator, Spliterator.ORDERED | Spliterator.IMMUTABLE), false); } 

Seems to work with all cases without duplication.

2 Comments

I like this solution a lot. Most answers split into two categories: (1) Reverse the collection and .stream() it, (2) Appeal to custom collectors. Both are absolutely unnecessary. Otherwise, it would've testified about some serious language expressiveness issue in JDK 8 itself. And your answer proves the opposite :)
5

The only way to reverse any arbitrary non-infinite stream is to read through the stream, capturing all values, and then stream through the captured values in reverse order. This means that at minimum, a full copy of the stream data must be stored in order to stream through it in reverse order.

Java 21

As of Java 21, the reversed() method on List makes reversing a general Stream a one-liner:

Stream<T> reversed = myStream.toList().reversed().stream(); 

IntStream and other primitive streams

Reversing a non-Object stream (e.g. an IntStream) is less straightforward. A simple (though not maximally efficient) solution would be to box it to an object Stream, reverse it, then convert it back.

IntStream reversedIntStream = intStream.boxed().toList().reversed().stream().mapToInt(Integer::intValue); 

A more efficient approach to reversing a non-Object stream is to stream to a primitive array, and then streaming through the array in reverse. The following is more than 6 times faster on my machine with a large array then the previous boxing/unboxing solution:

int[] intArray = intStream.toArray(); IntStream reversedIntStream = IntStream.iterate(intArray.length - 1, i -> i >= 0, i -> i - 1) .map(i -> intArray[i]); 

Pre-Java 21

Reversing a Stream prior to Java version 21 without using a customized collection type is more verbose, typically requiring an extra line to reverse the resulting list. The following Java 20 implementation streams to a mutable ArrayList, reverses the list, and then streams the list using .stream().

List<T> list = myStream.stream().collect(Collectors.toCollection(ArrayList::new)); Collections.reverse(list); Stream<T> reversed = list.stream(); 

Comments

3

Simplest way (simple collect - supports parallel streams):

public static <T> Stream<T> reverse(Stream<T> stream) { return stream .collect(Collector.of( () -> new ArrayDeque<T>(), ArrayDeque::addFirst, (q1, q2) -> { q2.addAll(q1); return q2; }) ) .stream(); } 

Advanced way (supports parallel streams in an ongoing way):

public static <T> Stream<T> reverse(Stream<T> stream) { Objects.requireNonNull(stream, "stream"); class ReverseSpliterator implements Spliterator<T> { private Spliterator<T> spliterator; private final Deque<T> deque = new ArrayDeque<>(); private ReverseSpliterator(Spliterator<T> spliterator) { this.spliterator = spliterator; } @Override @SuppressWarnings({"StatementWithEmptyBody"}) public boolean tryAdvance(Consumer<? super T> action) { while(spliterator.tryAdvance(deque::addFirst)); if(!deque.isEmpty()) { action.accept(deque.remove()); return true; } return false; } @Override public Spliterator<T> trySplit() { // After traveling started the spliterator don't contain elements! Spliterator<T> prev = spliterator.trySplit(); if(prev == null) { return null; } Spliterator<T> me = spliterator; spliterator = prev; return new ReverseSpliterator(me); } @Override public long estimateSize() { return spliterator.estimateSize(); } @Override public int characteristics() { return spliterator.characteristics(); } @Override public Comparator<? super T> getComparator() { Comparator<? super T> comparator = spliterator.getComparator(); return (comparator != null) ? comparator.reversed() : null; } @Override public void forEachRemaining(Consumer<? super T> action) { // Ensure that tryAdvance is called at least once if(!deque.isEmpty() || tryAdvance(action)) { deque.forEach(action); } } } return StreamSupport.stream(new ReverseSpliterator(stream.spliterator()), stream.isParallel()); } 

Note you can quickly extends to other type of streams (IntStream, ...).

Testing:

// Use parallel if you wish only revert(Stream.of("One", "Two", "Three", "Four", "Five", "Six").parallel()) .forEachOrdered(System.out::println); 

Results:

Six Five Four Three Two One 

Additional notes: The simplest way it isn't so useful when used with other stream operations (the collect join breaks the parallelism). The advance way doesn't have that issue, and it keeps also the initial characteristics of the stream, for example SORTED, and so, it's the way to go to use with other stream operations after the reverse.

Comments

3

Not purely Java8 but if you use guava's Lists.reverse() method in conjunction, you can easily achieve this:

List<Integer> list = Arrays.asList(1,2,3,4); Lists.reverse(list).stream().forEach(System.out::println); 

Comments

3

ArrayDeque are faster in the stack than a Stack or LinkedList. "push()" inserts elements at the front of the Deque

 protected <T> Stream<T> reverse(Stream<T> stream) { ArrayDeque<T> stack = new ArrayDeque<>(); stream.forEach(stack::push); return stack.stream(); } 

Comments

3
List newStream = list.stream().sorted(Collections.reverseOrder()).collect(Collectors.toList()); newStream.forEach(System.out::println); 

Comments

2

One could write a collector that collects elements in reversed order:

public static <T> Collector<T, ?, Stream<T>> reversed() { return Collectors.collectingAndThen(Collectors.toList(), list -> { Collections.reverse(list); return list.stream(); }); } 

And use it like this:

Stream.of(1, 2, 3, 4, 5).collect(reversed()).forEach(System.out::println); 

Original answer (contains a bug - it does not work correctly for parallel streams):

A general purpose stream reverse method could look like:

public static <T> Stream<T> reverse(Stream<T> stream) { LinkedList<T> stack = new LinkedList<>(); stream.forEach(stack::push); return stack.stream(); } 

Comments

2

For reference I was looking at the same problem, I wanted to join the string value of stream elements in the reverse order.

itemList = { last, middle, first } => first,middle,last

I started to use an intermediate collection with collectingAndThen from comonad or the ArrayDeque collector of Stuart Marks, although I wasn't happy with intermediate collection, and streaming again

itemList.stream() .map(TheObject::toString) .collect(Collectors.collectingAndThen(Collectors.toList(), strings -> { Collections.reverse(strings); return strings; })) .stream() .collect(Collector.joining()); 

So I iterated over Stuart Marks answer that was using the Collector.of factory, that has the interesting finisher lambda.

itemList.stream() .collect(Collector.of(StringBuilder::new, (sb, o) -> sb.insert(0, o), (r1, r2) -> { r1.insert(0, r2); return r1; }, StringBuilder::toString)); 

Since in this case the stream is not parallel, the combiner is not relevant that much, I'm using insert anyway for the sake of code consistency but it does not matter as it would depend of which stringbuilder is built first.

I looked at the StringJoiner, however it does not have an insert method.

Comments

2

Reversing string or any Array

(Stream.of("abcdefghijklm 1234567".split("")).collect(Collectors.collectingAndThen(Collectors.toList(),list -> {Collections.reverse(list);return list;}))).stream().forEach(System.out::println); 

split can be modified based on the delimiter or space

Comments

2

This method works with any Stream and is Java 8 compliant:

Stream<Integer> myStream = Stream.of(1, 2, 3, 4, 5); myStream.reduce(Stream.empty(), (Stream<Integer> a, Integer b) -> Stream.concat(Stream.of(b), a), (a, b) -> Stream.concat(b, a)) .forEach(System.out::println); 

Comments

2

Based on @stuart-marks's answer, but without casting, function returning stream of list elements starting from end:

public static <T> Stream<T> reversedStream(List<T> tList) { final int size = tList.size(); return IntStream.range(0, size) .mapToObj(i -> tList.get(size - 1 - i)); } // usage reversedStream(list).forEach(System.out::println); 

Comments

2

How about reversing the Collection backing the stream prior?

import java.util.Collections; import java.util.List; public void reverseTest(List<Integer> sampleCollection) { Collections.reverse(sampleCollection); // remember this reverses the elements in the list, so if you want the original input collection to remain untouched clone it first. sampleCollection.stream().forEach(item -> { // you op here }); } 

Comments

1

Answering specific question of reversing with IntStream, below worked for me:

IntStream.range(0, 10) .map(x -> x * -1) .sorted() .map(Math::abs) .forEach(System.out::println); 

Comments

1

In all this I don't see the answer I would go to first.

This isn't exactly a direct answer to the question, but it's a potential solution to the problem.

Just build the list backwards in the first place. If you can, use a LinkedList instead of an ArrayList and when you add items use "Push" instead of add. The list will be built in the reverse order and will then stream correctly without any manipulation.

This won't fit cases where you are dealing with primitive arrays or lists that are already used in various ways but does work well in a surprising number of cases.

Comments

1

the simplest solution is using List::listIterator and Stream::generate

List<Integer> list = Arrays.asList(1, 2, 3, 4, 5); ListIterator<Integer> listIterator = list.listIterator(list.size()); Stream.generate(listIterator::previous) .limit(list.size()) .forEach(System.out::println); 

5 Comments

It's worth adding that Stream.generate() generates in infinite stream, so the call to limit() is very important here.
@andrebrait even worse, Stream.generate() generates an unordered stream, so there is no guaranty that limit(…) will pick up the first items (as “first” has no meaning here). Or in this specific case, the code may fail with a NoSuchElementException.
@Holger ordered/unordered is only gonna make a difference if the stream is parallel. The stream is still gonna just be generated by calling the supplier to get each item, so the order is simply whatever order your function returns items in. I have used it quite a bit, in fact. Even if parallel, IIRC, it won't call your function more than the limit. Can it really result in such an exception?
@andrebrait you’re developing against a contract and the contract of Stream.generate(…).limit(…) is that it may pick arbitrary elements instead of the “first” elements, because “first” has no meaning for an unordered Stream. Even if it happens to do the intended thing in one setup you shouldn’t rely on things that are not guaranteed. Regarding exceptions, I got one right ins the first try: ideone.com/Zy1KkM
@Holger I can confirm the exception does happen indeed, but the ordering matter only matters for parallel streams, so I'm gonna agree it's not the most solid implemention, but I wouldn't call it a violation of contract because the contract makes it pretty explicit it's an unordered sequential stream, unless you make it parallel afterwards. But yeah, not very solid.
0

Java 8 way to do this:

 List<Integer> list = Arrays.asList(1,2,3,4); Comparator<Integer> comparator = Integer::compare; list.stream().sorted(comparator.reversed()).forEach(System.out::println); 

4 Comments

This is sorting in reverse order, not reverting a list.
@JochenBedersdorfer — In fairness, this question is asking (at least implicitly) about three different things: How to reverse a stream in general, how to generate a reverse range of integers, and why a specific solution using Stream.compare produces a specific error message when changed to use an IntStream. This answer addresses a different, specific problem with that specific solution in the question: namely that it didn't actually sort Arrays.asList(1,2,3,4) in reverse, despite using Stream.sorted in an apparent attempt to do so.
@M.Justin did you just really comment on my 2016 comment? Also, the way the above answer was written (with 0 upvotes) implies that it is a solution. It is not. Also my comment is very clear: The code presented does not "revert a list". Is that sufficiently clear for you now?
@JochenBedersdorfer 1. I did indeed. It's a live (not deleted) comment on a live answer to a live question, so it's still part of the public Q&A. 2. Agreed, the answer's introduction "Java 8 way to do this:" implies it's a solution to the entire stated problem. It's therefore not ideal in my opinion. 3. I agree that your comment was clear (I assume "reverting" was a typo and was intended to be "reversing"). I was addressing what I perceive to be the implied intent behind your comment, which is that since it is sorting in reverse order, not reversing a list, this is not a good answer.
0

This is how I do it.

I don't like the idea of creating a new collection and reverse iterating it.

The IntStream#map idea is pretty neat, but I prefer the IntStream#iterate method, for I think the idea of a countdown to Zero better expressed with the iterate method and easier to understand in terms of walking the array from back to front.

import static java.lang.Math.max; private static final double EXACT_MATCH = 0d; public static IntStream reverseStream(final int[] array) { return countdownFrom(array.length - 1).map(index -> array[index]); } public static DoubleStream reverseStream(final double[] array) { return countdownFrom(array.length - 1).mapToDouble(index -> array[index]); } public static <T> Stream<T> reverseStream(final T[] array) { return countdownFrom(array.length - 1).mapToObj(index -> array[index]); } public static IntStream countdownFrom(final int top) { return IntStream.iterate(top, t -> t - 1).limit(max(0, (long) top + 1)); } 

Here are some tests to prove it works:

import static java.lang.Integer.MAX_VALUE; import static org.junit.Assert.*; @Test public void testReverseStream_emptyArrayCreatesEmptyStream() { Assert.assertEquals(0, reverseStream(new double[0]).count()); } @Test public void testReverseStream_singleElementCreatesSingleElementStream() { Assert.assertEquals(1, reverseStream(new double[1]).count()); final double[] singleElementArray = new double[] { 123.4 }; assertArrayEquals(singleElementArray, reverseStream(singleElementArray).toArray(), EXACT_MATCH); } @Test public void testReverseStream_multipleElementsAreStreamedInReversedOrder() { final double[] arr = new double[] { 1d, 2d, 3d }; final double[] revArr = new double[] { 3d, 2d, 1d }; Assert.assertEquals(arr.length, reverseStream(arr).count()); Assert.assertArrayEquals(revArr, reverseStream(arr).toArray(), EXACT_MATCH); } @Test public void testCountdownFrom_returnsAllElementsFromTopToZeroInReverseOrder() { assertArrayEquals(new int[] { 4, 3, 2, 1, 0 }, countdownFrom(4).toArray()); } @Test public void testCountdownFrom_countingDownStartingWithZeroOutputsTheNumberZero() { assertArrayEquals(new int[] { 0 }, countdownFrom(0).toArray()); } @Test public void testCountdownFrom_doesNotChokeOnIntegerMaxValue() { assertEquals(true, countdownFrom(MAX_VALUE).anyMatch(x -> x == MAX_VALUE)); } @Test public void testCountdownFrom_givesZeroLengthCountForNegativeValues() { assertArrayEquals(new int[0], countdownFrom(-1).toArray()); assertArrayEquals(new int[0], countdownFrom(-4).toArray()); } 

Comments

0

What's the proper generic way to reverse a stream?

If the stream does not specify an encounter order, don't. (!s.spliterator().hasCharacteristics(java.util.Spliterator.ORDERED))

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.