228

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?

Nilanka Manoj
  • 3,527
  • 4
  • 17
  • 48
vach
  • 10,571
  • 12
  • 68
  • 106
  • 2
    An `IntStream` has no `.sorted(Comparator)` method; you have to go through a `Stream` first and reverse there before yielding an `IntStream` – fge Jun 03 '14 at 08:23
  • Ok, I've found it, you need to use .boxed() and then .sorted() – vach Jun 03 '14 at 08:24
  • 5
    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. – Stuart Marks Jun 03 '14 at 08:39
  • 3
    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`? – chiccodoro Jun 03 '14 at 08:54
  • 10
    You can't reverse a stream in general - for example a stream may be inifinite. – assylias Jun 03 '14 at 09:01
  • To "reverse the stream" you will first need to collect all items. You might try to use a stack because its LIFO nature will reverse the items after pushing and pulling back, something like: `stream.collect(Collectors.toCollection(Stack::new)).stream()`. (As assylias commented, you can't do that on an infinite stream. But that holds for sorting, too. – chiccodoro Jun 03 '14 at 09:03
  • Yes I've come up with this, but I tought there will be a "cleaner" way to do that. I think you can put it as an answer, and guys above are right my questions are different indeed, one about reversing the other one about ordering. Anyway I think others who might search and navigate to this question will looking for reversing part of this discussion. So please post it as an answer. – vach Jun 03 '14 at 09:08
  • 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. – Manu Manjunath Dec 10 '15 at 12:56
  • @assylias This doesn't make sense. For the same reason there is no point on collecting a stream or using loops in general (cause we may run into the halting problem), but we can do both. – tur1ng Sep 29 '18 at 14:31
  • `IntStream.rangeClosed(-n, 0).map(i -> -i)` will produce elements in reversed order i.e. `n, n-1, n-2, ... , 0`. – bjmi Sep 21 '21 at 15:50

31 Answers31

110

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.

Stuart Marks
  • 127,867
  • 37
  • 205
  • 259
  • 19
    Alternatively: `IntStream.iterate(to-1, i->i-1).limit(to-from)` – Holger Jun 03 '14 at 11:41
  • 3
    @Holger Unfortunately, that solution doesn't handle overflow correctly. – Brandon Jan 28 '16 at 23:51
  • 5
    @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. – Holger Jan 29 '16 at 09:48
  • Or `IntStream.rangeClosed(1, to - from).map(i -> to-i)` (see [bjmi's comment](https://stackoverflow.com/questions/24010109/java-8-stream-reverse-order/36192274#comment122436338_24010109), too). – greybeard Jan 10 '22 at 10:02
73

Elegant solution

List<Integer> list = Arrays.asList(1,2,3,4);
list.stream()
    .sorted(Collections.reverseOrder()) // Method on Stream<Integer>
    .forEach(System.out::println);
nnym
  • 26
  • 1
  • 8
Kishan B
  • 4,731
  • 1
  • 19
  • 11
  • 12
    It is elegant but not fully working as it seems as elements of the list are required to be `Comparable`... – Krzysztof Wolny Aug 04 '16 at 15:11
  • 102
    That's assuming we want elements to be *sorted* in reverse order. The question is about reversing the order of a stream. – Dillon Ryan Redding Nov 04 '18 at 14:24
  • @KrzysztofWolny you can pass a comparator function to reverseOrder(), so that shouldn't be too much of a bother – Dávid Leblay Sep 21 '20 at 12:45
  • 1
    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. – vach Nov 12 '22 at 18:28
57

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)
Venkata Raju
  • 4,866
  • 3
  • 27
  • 36
  • 5
    Some stream operation, such as `sorted` and `distinct` actually store an intermediate result. See the [package API docs](http://docs.oracle.com/javase/8/docs/api/java/util/stream/package-summary.html#StreamOps) for some information about that. – Lii Sep 25 '14 at 09:08
  • @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) – Venkata Raju Oct 16 '15 at 14:13
  • 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. – Manu Manjunath Dec 10 '15 at 12:54
  • 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. – Beezer Dec 02 '16 at 04:56
  • 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. – Cubic Oct 03 '19 at 13:13
41

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});
}
Community
  • 1
  • 1
Brandon
  • 2,367
  • 26
  • 32
  • awesome and simple. Is this from some opensource utilty? (the Estreams thing) or some piece of your code? – vach Jan 06 '16 at 09:47
  • 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. – Brandon Jan 06 '16 at 20:54
  • 4
    Okay…“awesome and simple”… Is there any case that this solution handles, which [Stuart Marks’ even simpler solution](http://stackoverflow.com/a/24011264/2711488) didn’t already handle more than one and a half year ago? – Holger Jan 28 '16 at 19:24
  • 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. – Brandon Jan 28 '16 at 23:43
  • I encourage @vach to accept his instead of mine. Once my suggested edit of his post is accepted, I'll delete my answer altogether. – Brandon Jan 28 '16 at 23:48
  • 1
    @vach, you may use by [`StreamEx`](https://github.com/amaembo/streamex) specifying step: `IntStreamEx.rangeClosed(from-1, to, -1)` – Tagir Valeev Jan 29 '16 at 01:57
  • @TagirValeev thanks, i've seen this lib few places, on habrahabr also, i'm gonna check it out for sure, seems like a good tool – vach Jan 30 '16 at 11:43
  • What about `IntStream.range(-to, -from).map(i -> -i-1)` or `IntStream.rangeClosed(-to, -from).map(i -> -i)`? – neXus Nov 28 '17 at 09:25
  • @neXus: Both of your proposals fail on the second to last test above: `assertArrayEquals(revRange(MIN_VALUE, MIN_VALUE + 1).toArray(), new int[]{MIN_VALUE});`. – Brandon Nov 28 '17 at 20:10
37

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 at the end)

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]

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]

luke
  • 3,435
  • 33
  • 41
  • 2
    `(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 Nov 12 '20 at 13:09
  • @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. – luke Nov 19 '20 at 11:26
  • I revised my answer according to yankee comment. Now the answer should be correct. – luke Nov 30 '20 at 10:46
22

without external lib...

import java.util.List;
import java.util.Collections;
import java.util.stream.Collector;

public class MyCollectors {

    public static <T> Collector<T, ?, List<T>> toListReversed() {
        return Collectors.collectingAndThen(Collectors.toList(), l -> {
            Collections.reverse(l);
            return l;
        });
    }

}
comonad
  • 5,134
  • 2
  • 33
  • 31
  • 1
    `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. – M. Justin Mar 02 '23 at 17:13
13

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);
    }
}
lexicalscope
  • 7,158
  • 6
  • 37
  • 57
11

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);
Neuron
  • 5,141
  • 5
  • 38
  • 59
YujiSoftware
  • 1,281
  • 14
  • 15
  • 27
    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)` – wilmol Nov 15 '19 at 03:08
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);
John McClean
  • 5,225
  • 1
  • 22
  • 30
  • 1
    Nice didnt know about this project – vach Jun 11 '15 at 20:06
  • 1
    cyclops now also comes with [Spliterators](http://static.javadoc.io/com.aol.cyclops/cyclops-sequence-api/6.0.1/com/aol/cyclops/sequence/spliterators/package-frame.html) for efficient Stream reversal (currently for Ranges, arrays and Lists). Creating cyclops [SequenceM](http://static.javadoc.io/com.aol.cyclops/cyclops-sequence-api/6.0.1/com/aol/cyclops/sequence/SequenceM.html) Stream extension with SequenceM.of, SequenceM.range or SequenceM.fromList will automatically take advantage of efficiently reversible spliterators. – John McClean Sep 15 '15 at 21:10
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...
vach
  • 10,571
  • 12
  • 68
  • 106
  • 2
    This is only an answer to your "specific question" but not to your "general question". – chiccodoro Jun 03 '14 at 08:55
  • 14
    [`Collections.reverseOrder()`](http://docs.oracle.com/javase/8/docs/api/java/util/Collections.html#reverseOrder--) exists since Java 1.2 and works with `Integer`… – Holger Jun 03 '14 at 11:36
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.

lukens
  • 479
  • 4
  • 10
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.

Jerome
  • 1,225
  • 2
  • 12
  • 23
  • 1
    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 :) – vitrums Jul 06 '20 at 18:44
  • (see [Adrian's May '19 answer](https://stackoverflow.com/a/56289986/3789665), too.) – greybeard Jan 10 '22 at 10:28
4

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.
Oleksandr Pyrohov
  • 14,685
  • 6
  • 61
  • 90
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.

Tet
  • 1,155
  • 10
  • 14
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);
Jeffrey
  • 1,068
  • 2
  • 15
  • 25
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();
}
Prakash Pazhanisamy
  • 997
  • 1
  • 15
  • 25
Dotista
  • 404
  • 3
  • 12
3
List newStream = list.stream().sorted(Collections.reverseOrder()).collect(Collectors.toList());
        newStream.forEach(System.out::println);
c0der
  • 18,467
  • 6
  • 33
  • 65
siddmuk2005
  • 178
  • 2
  • 11
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();
}
SlavaSt
  • 1,493
  • 1
  • 16
  • 19
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.

bric3
  • 40,072
  • 9
  • 91
  • 111
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

Hessam
  • 1,377
  • 1
  • 23
  • 45
sai manoj
  • 21
  • 1
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);
David Larochette
  • 1,200
  • 10
  • 18
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
    });
}
M. Justin
  • 14,487
  • 7
  • 91
  • 130
levenshtein
  • 879
  • 8
  • 4
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);
Girish Jain
  • 595
  • 4
  • 9
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.

Bill K
  • 62,186
  • 18
  • 105
  • 157
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);
Adrian
  • 2,984
  • 15
  • 27
  • It's worth adding that ```Stream.generate()``` generates in infinite stream, so the call to ```limit()``` is very important here. – andrebrait Jul 05 '19 at 08:43
1

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);
aksh1618
  • 2,245
  • 18
  • 37
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());
}
Brixomatic
  • 381
  • 4
  • 16
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))

greybeard
  • 2,249
  • 8
  • 30
  • 66
0

The only way to reverse any general 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.

JEP 431: Sequenced Collections in the upcoming version 21 of Java adds (among other things) a reversed() method List, which provides a reversed view of the list. Using this feature makes reversing a general Stream a one-liner:

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

Accomplishing the same thing with Java version 20 without using a customized collection type is more verbose, typically requiring an extra step of reversing the resulting list. The following Java 20 implementation streams to a List, reverses the list, and then return a stream using .toStream().

List<T> list = myStream.stream().collect(Collectors.toCollection(ArrayList::new));
Collections.reverse(list);
Stream<T> reversed = list.stream();
M. Justin
  • 14,487
  • 7
  • 91
  • 130
-1

The most generic and the easiest way to reverse a list will be :

public static <T> void reverseHelper(List<T> li){

 li.stream()
.sorted((x,y)-> -1)
.collect(Collectors.toList())
.forEach(System.out::println);

    }
  • 4
    You violate the contract of `Comparator`. As a result nobody can guarantee you that this "trick" will work in any future Java version with any sorting algorithm. The same trick does not work for parallel stream, for example, as parallel sorting algorithm uses `Comparator` in different way. For sequential sort it works purely by chance. I would not recommend anybody to use this solution. – Tagir Valeev Oct 21 '15 at 08:51
  • 1
    Also it doesn't work when you set `System.setProperty("java.util.Arrays.useLegacyMergeSort", "true");` – Tagir Valeev Oct 21 '15 at 08:53
  • I thought it was about just printing things in reverse order not in sorted order (ie. descending order), and it works with parallel stream too : `public static void reverseHelper(List li){ li.parallelStream() .sorted((x,y)->-1) .collect(Collectors.toList()) .forEach(System.out::println); }` – parmeshwor11 Oct 21 '15 at 09:27
  • 1
    Try `reverseHelper(IntStream.range(0, 8193).boxed().collect(Collectors.toList()))` (result may depend on number of cores though). – Tagir Valeev Oct 21 '15 at 10:51
-1

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);
Anthony
  • 12,407
  • 12
  • 64
  • 88