34

When I reverse iterate over an ArrayList I am getting a IndexOutOfBoundsException. I tried doing forward iteration and there is no problem. I expect and know that there are five elements in the list. The code is below:

Collection rtns = absRtnMap.values();
List list = new ArrayList(rtns);
Collections.sort(list);

for(int j=list.size();j>0;j=j-1){
  System.out.println(list.get(j));
}

Forward iteration - which is working fine, but not useful for me:

for(int j=0;j<list.size();j++){
    System.out.println(list.isEmpty());
    System.out.println(list.get(j));
} // this worked fine

The error:

Exception in thread "Timer-0" java.lang.IndexOutOfBoundsException: Index: 3, Size: 3
    at java.util.ArrayList.RangeCheck(Unknown Source)
    at java.util.ArrayList.get(Unknown Source)
    at model.Return.getReturnMap(Return.java:61)
    at controller.Poller$1.run(Poller.java:29)
    at java.util.TimerThread.mainLoop(Unknown Source)
    at java.util.TimerThread.run(Unknown Source)

Also if anyone knows of a better idiom for reverse iteration I would be happy to try that out.

David Z
  • 128,184
  • 27
  • 255
  • 279
Ankur
  • 50,282
  • 110
  • 242
  • 312

9 Answers9

90

Avoid indexes altogether? How about:

for (ListIterator iterator = list.listIterator(list.size()); iterator.hasPrevious();) {
  final Object listElement = iterator.previous();
}
Sualeh Fatehi
  • 4,700
  • 2
  • 24
  • 28
  • 1
    Well, it's more verbose than the indexed version. – Seun Osewa Jan 15 '10 at 21:44
  • 16
    @Seun - that's because it uses more words to explain more clearly. I would actually break it up into a `ListIterator iterator = list.listIterator(list.size()); while (iterator.hasPrevious()){ ...iterator.previous(); }`, since, you're not using the incrementer in the `for` statement. – Peter Ajtai Nov 15 '11 at 18:30
  • 7
    +1, this has the added benefit of working efficiently with LinkedList, which uses its own linked ListIterator instead of index access, which is slow for LinkedLists. – Sam Barnum Aug 20 '12 at 20:01
  • @PeterAjtai yes, that's basically the answer on https://stackoverflow.com/questions/2102499/iterating-through-a-list-in-reverse-order-in-java – Stéphane Gourichon Jun 13 '16 at 10:11
69

Start the iteration at list.size() - 1 because array (or ArrayList) elements are numbered from 0 up through 1 less than the size of the list. This is a fairly standard idiom:

for (int j = list.size() - 1; j >= 0; j--) {
    // whatever
}

Note that your forward iteration works because it stops before reaching list.size().

Koray Tugay
  • 22,894
  • 45
  • 188
  • 319
David Z
  • 128,184
  • 27
  • 255
  • 279
  • 1
    Yep thanks, everyone, just came back to say what a silly question it was. And already had several answers. Thanks. – Ankur Feb 24 '09 at 02:50
25

I know this is an old question, but Java contains a Collections.reverse( List<T> ) method. Why wouldn't you just reverse it and do forward iteration?

Snailer
  • 3,777
  • 3
  • 35
  • 46
  • 2
    That's by far the best answer available, judging by the title of the question: "Reverse iteration" and only here this is mentioned at all. I arrived through Google, and this is the only answer that worked for me. – K.Steff Jan 23 '12 at 18:50
  • 1
    What is the complexity of this? Does it copy the whole list, or just returns a reverse pointer? – Torandi Apr 10 '12 at 21:10
  • I believe (through my limited use of it) it actually performs the reversing on the list itself, and returns void. So, a List reversed should be reversed again to revert to it's normal state. – Snailer Apr 11 '12 at 23:58
  • 9
    Adding to what @Snailer already mentioned - it will also be very slow for very large list. going reverse via index or iterator is better... especially if you need the original list again. – Sid Malani May 30 '12 at 13:47
  • 3
    That's true. It's certainly not the most performance-savvy method. But for most applications, I prefer more readable code over an unnoticeable performance loss. If you're performing many iterations over large lists, then don't use this! – Snailer May 30 '12 at 15:02
  • It's important to note that Collections.reverse can't be used if your list is immutable. – Michael Oliver Nov 21 '14 at 02:13
  • 2
    Be careful with using this answer. Reversing a list and then iterating over it is *very* different to iterating over a list in reverse. The former leaves the list in a different state to when you started, the latter doesn't. – Mark Booth Nov 03 '17 at 14:51
  • Best answer, although be aware that this changes the order of the list whereas iterating through it in reverse order does not. – fantom Mar 12 '19 at 04:43
11

The most elegant way is to reverse the array and then use a direct (or even implicit) iterator :

Collections.reverse(arrayList);
for (Object item : arrayList) {
    ...
}
Stephan
  • 41,764
  • 65
  • 238
  • 329
el fuego
  • 821
  • 9
  • 18
  • 6
    As stated in another answer to this question above (http://stackoverflow.com/a/6575124/877472), the `Collections.reverse` method reverses the collection passed in, meaning it would have to be reversed again if you wanted to use it in its original orientation, which can be costly for very large collections. – Paul Richter Sep 11 '13 at 20:06
11

The list.size() is past the last allowable index.

for(int j = list.size() - 1; j >= 0; j--) {
  System.out.println(list.get(j));
}
Frits
  • 7,341
  • 10
  • 42
  • 60
Clint
  • 8,988
  • 1
  • 26
  • 40
  • Actually no, list.size() is not an allowable index - it's one beyond that - which is why you are using size() -1 in your example :) – matt b Feb 24 '09 at 03:08
  • Glad I read every solution here before posting my own, because this was basically it! – HoldOffHunger Jun 06 '17 at 23:49
4

Java arrays are zero-indexed. You will have to set j = list.size() - 1 and continue until j = 0.

Coxy
  • 8,844
  • 4
  • 39
  • 62
3

If the lists are fairly small so that performance is not a real issue, one can use the reverse-metod of the Lists-class in Google Guava. Yields pretty for-each-code, and the original list stays the same. Also, the reversed list is backed by the original list, so any change to the original list will be reflected in the reversed one.

import com.google.common.collect.Lists;

[...]

final List<String> myList = Lists.newArrayList("one", "two", "three");
final List<String> myReverseList = Lists.reverse(myList);

System.out.println(myList);
System.out.println(myReverseList);

myList.add("four");

System.out.println(myList);
System.out.println(myReverseList);

Yields the following result:

[one, two, three]
[three, two, one]
[one, two, three, four]
[four, three, two, one]

Which means that reverse iteration of myList can be written as:

for (final String someString : Lists.reverse(myList) {
    //do something
}
Tobb
  • 11,850
  • 6
  • 52
  • 77
1

You can do this if you are comfortable with foreach loop.

List<String> list = new ArrayList<String>();
list.add("ABC");
list.add("DEF");
list.add("GHI");

ListIterator<String> listIterator = list.listIterator(list.size());

while(listIterator.hasPrevious()){
  System.out.println(listIterator.previous());
}
Gopala Krishna
  • 117
  • 1
  • 12
-1

You can reverse by one line that is

Collections.reverse(list);

ArrayList arrayList = new ArrayList();

arrayList.add("A");
arrayList.add("B");

System.out.println("Before Reverse Order : " + arrayList);

Collections.reverse(arrayList);

System.out.println("After Reverse : " + arrayList);

Output

Before Reverse Order : [A, B]
After Reverse : [B, A]
Dharmbir Singh
  • 17,485
  • 5
  • 50
  • 66