Explain Codes LogoExplain Codes Logo

Can one do a for each loop in java in reverse order?

java
iterators
collections
best-practices
Alex KataevbyAlex Kataev·Oct 18, 2024
TLDR

Here's how you can reverse a for-each loop using a ListIterator:

List<String> list = Arrays.asList("a", "b", "c"); ListIterator<String> iter = list.listIterator(list.size()); while (iter.hasPrevious()) System.out.println(iter.previous());

Output: c b a

We utilize ListIterator's hasPrevious() and previous() methods for reverse iteration.

Crafting a custom solution

Building a Reversible Iterable

If reverse traversals are common in your project, a reusable class may save the day! Here's a decorator providing reverse iteration over a List without modifying it:

public class Reversed<T> implements Iterable<T> { private final List<T> original; public Reversed(List<T> original) { this.original = original; } public Iterator<T> iterator() { final ListIterator<T> i = original.listIterator(original.size()); return new Iterator<T>() { public boolean hasNext() { return i.hasPrevious(); // Looking backwards! } public T next() { return i.previous(); // Moving backwards, not a moonwalk though. } public void remove() { i.remove(); // We're efficient, not just backward. } }; } // Usage with for-each loop // for (String element : new Reversed<>(list)) { ... } }

Rows of code were flipped just so you can flip through a List backwards.

Voice of practicality: Google Guava

If you trust a library to own your jarfile, Google Guava has got you covered:

List<String> reversed = Lists.reverse(list); for(String element : reversed) { System.out.println(element); }

This is an efficient maneuver, but weigh the costs before you add an external library.

Minding Efficiency with ArrayList

ArrayList has random access, meaning it proudly provides constant-time iterations over elements. A simple for loop can sometimes be more efficient:

for (int i = list.size() - 1; i >= 0; i--) { String element = list.get(i); // Do something, not always simple stuff. }

When using Collections.reverse(), remember to call it outside the loop:

Collections.reverse(list); // Now iterate normally with a for-each loop

Careful, though, this method changes your list's original selection.

Handling divider situations

Cloning safely

For reversing a list via cloning, remember: clone() makes a shallow copy. When handling mutable objects, go for a deep copy to avoid unintended ripple effects:

List<String> clone = deepCopy(list); Collections.reverse(clone);

Synchronizing for safety

If the list is modified during iteration, wrap the iteration inside a synchronized block or use concurrent collections to prevent the dreaded race:

synchronized(list) { for (String element : new Reversed<>(list)) { // It's a synchronized world after all! } }

Removing elements while reversing

With a ListIterator, you can remove items while iterating in reverse, unlike a for-each loop:

while(iter.hasPrevious()) { if (countDracula(iter.previous())) { iter.remove(); // I never liked garlic. } }

But watch out for your steps, you don't want to trip over an unexpected ConcurrentModificationException.