本文共 2919 字,大约阅读时间需要 9 分钟。
Java中循环遍历元素,一般有for循环遍历,foreach循环遍历,iterator遍历。
举例
定义一个List对象Listlist = new ArrayList<>();list.add("1");list.add("2");list.add("3");
for (int i = 0; i < list.size(); i++) { System.out.println(i + ":" + list.get(i)); String s = list.get(i); if ("1".equals(s)) { list.remove(s); }}System.out.println(list);
输出结果为
0:11:3[2, 3]
这种删除方法明显有问题,遗漏了被删除元素的下一个元素。
这种情况下,如果被删除元素切好是List中最后一个元素,则输出结果恰好正常。 解决方法: 遗漏元素是因为删除元素后,List的size已经减1,但i不变,则i位置元素等于被跳过,不在循环中处理。 若if代码块中调用remove函数后,加上i–,则能避免这种错误。Iteratoriterator = list.iterator(); while (iterator.hasNext()){ String str = iterator.next(); System.out.println(str); if("2".equals(str)) { iterator.remove(); }}System.out.println(list);
输出结果为
123[1, 3]
最安全的遍历中删除元素方法。
借用了Iterator,删除元素用的也是Iterator的remove方法,而不是List中的。for (String s : list) { System.out.println(s); if ("2".equals(s)) { list.remove(s); }}
删除元素2:正常输出
1 2 [1, 3]
删除元素1或3:报错
java.util.ConcurrentModificationException at java.util.ArrayList$Itr.checkForComodification(ArrayList.java:909) at java.util.ArrayList$Itr.next(ArrayList.java:859)
foreach的本质
通过反编译,foreach的代码实现如下:Iterator itr3 = list.iterator();while(itr3.hasNext()) { String s = (String)itr3.next(); System.out.println(s); if ("2".equals(s)) { list.remove(s); }}
对比后发现,foreach实质上也是使用Iterator进行遍历。
不同的地方在于,一个使用Iterator的删除方法,一个使用List的删除方法。 问题出在 list.remove(s); 代码中。我们查看一下ArrayList的报错相关代码。代码如下:public boolean hasNext() { return cursor != size;}public E next() { checkForComodification();//859行 int i = cursor; if (i >= size) throw new NoSuchElementException(); Object[] elementData = ArrayList.this.elementData; if (i >= elementData.length) throw new ConcurrentModificationException(); cursor = i + 1; return (E) elementData[lastRet = i];}final void checkForComodification() { if (modCount != expectedModCount) throw new ConcurrentModificationException();//909行}public boolean remove(Object o) { ··· fastRemove(index); ···}private void fastRemove(int index) { modCount++; ···}
其中,size和modCount为ArrayList属性;cursor和expectedModCount为ArrayList.Iterator属性。
输出分析
list.removeIf(e->e.equals("2"));
list = list.stream().filter(l->!l.equals("2")).collect(Collectors.toList());
转载博客: