通过ArrayList反向迭代会产生IndexOutOfBoundsException

Ank*_*kur 31 java iteration reverse arraylist

当我反复遍历ArrayList时,我得到一个IndexOutOfBoundsException.我尝试进行前向迭代,没有问题.我希望并知道列表中有五个元素.代码如下:

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));
}
Run Code Online (Sandbox Code Playgroud)

前向迭代 - 工作正常,但对我没用:

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

错误:

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)
Run Code Online (Sandbox Code Playgroud)

此外,如果有人知道反向迭代更好的习语,我很乐意尝试这一点.

Sua*_*ehi 87

完全避免索引?怎么样:

for (ListIterator iterator = list.listIterator(list.size()); iterator.hasPrevious();) {
  final Object listElement = iterator.previous();
}
Run Code Online (Sandbox Code Playgroud)

  • @Seun - 那是因为它使用更多的词来更清楚地解释.我实际上将它分解为`ListIterator iterator = list.listIterator(list.size()); while(iterator.hasPrevious()){... iterator.previous(); 因为,你没有在`for`语句中使用增量器. (14认同)
  • +1,这具有使用LinkedList高效工作的额外好处,LinkedList使用自己的链接ListIterator而不是索引访问,这对于LinkedLists来说很慢. (7认同)

Dav*_*d Z 63

开始迭代,list.size() - 1因为数组(或ArrayList)元素的编号从0到1小于列表的大小.这是一个相当标准的习语:

for (int j = list.size() - 1; j >= 0; j--) {
    // whatever
}
Run Code Online (Sandbox Code Playgroud)

请注意,您的前向迭代有效,因为它到达之前停止list.size().

  • 不是一个愚蠢的问题!它帮助了我:-) (3认同)

Sna*_*ler 28

我知道这是一个老问题,但Java包含一个Collections.reverse( List<T> )方法.你为什么不反转它并进行前向迭代?

  • 添加到@Snailer已经提到的内容 - 对于非常大的列表来说它也会非常慢.通过索引或迭代器反向更好...特别是如果你再次需要原始列表. (8认同)
  • 确实如此.它当然不是最精通性能的方法.但是对于大多数应用程序,我更喜欢更易读的代码,而不是显着的性能损失.如果您在大型列表上执行多次迭代,则不要使用它! (3认同)
  • 从问题的标题来看:“反向迭代”,这是迄今为止可用的最佳答案,仅在这里完全提及。我是通过Google到达的,这是唯一对我有用的答案。 (2认同)
  • 使用这个答案时要小心。反转列表然后迭代它与反向迭代列表“非常”不同。前者使列表处于与开始时不同的状态,后者则不然。 (2认同)

el *_*ego 12

最优雅的方法是反转数组,然后使用直接(甚至隐式)迭代器:

Collections.reverse(arrayList);
for (Object item : arrayList) {
    ...
}
Run Code Online (Sandbox Code Playgroud)

  • 正如上面这个问题的另一个答案(http://stackoverflow.com/a/6575124/877472)所述,`Collections.reverse`方法会反转传入的集合,这意味着如果你想要的话,它必须再次反转使用它的原始方向,这对于非常大的集合来说可能是昂贵的. (4认同)

Cli*_*int 11

list.size()超过了最后一个允许的索引.

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