我是靠谱客的博主 会撒娇衬衫,这篇文章主要介绍为什么不建议用增强for循环删除列表中元素(通俗易懂版)分析然后最后解决方案扩充,现在分享给大家,希望可以做个参考。

目录

分析

首先

然后

最后

解决方案

扩充


首先我们来看错误案例

复制代码
1
2
3
4
5
6
7
8
9
10
11
12
@Test public void doSomething(){ ArrayList<String> list = new ArrayList<String>(); list.add("昨天"); list.add("今天"); list.add("明天"); for (String s : list){ if (s.equals("昨天")){ list.remove(s); } } }

这个将会报错

java.util.ConcurrentModificationException

分析

首先

调用了三次add,我们来看list中add的源码(不会的可以看我关于源码博文的list讲解),最终调用了modCount++。这个modCount变量就是为了记录操作list的次数,详细可以看源码。

复制代码
1
2
3
4
5
6
7
private void ensureExplicitCapacity(int minCapacity) { modCount++; // overflow-conscious code if (minCapacity - elementData.length > 0) grow(minCapacity); }

然后

我们都知道增强for循环,相当于是迭代器的语法糖。ArrayList中迭代器的方法源码

复制代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
public Iterator<E> iterator() { return new Itr(); } //Itr为内部类 private class Itr implements Iterator<E> { int cursor; // index of next element to return int lastRet = -1; // index of last element returned; -1 if no such int expectedModCount = modCount; //赋值给expectedModCount Itr() {} public boolean hasNext() { return cursor != size; } @SuppressWarnings("unchecked") public E next() { checkForComodification(); 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]; } public void remove() { if (lastRet < 0) throw new IllegalStateException(); checkForComodification(); try { ArrayList.this.remove(lastRet); cursor = lastRet; lastRet = -1; expectedModCount = modCount; } catch (IndexOutOfBoundsException ex) { throw new ConcurrentModificationException(); } } @Override @SuppressWarnings("unchecked") public void forEachRemaining(Consumer<? super E> consumer) { Objects.requireNonNull(consumer); final int size = ArrayList.this.size; int i = cursor; if (i >= size) { return; } final Object[] elementData = ArrayList.this.elementData; if (i >= elementData.length) { throw new ConcurrentModificationException(); } while (i != size && modCount == expectedModCount) { consumer.accept((E) elementData[i++]); } // update once at end of iteration to reduce heap write traffic cursor = i; lastRet = i - 1; checkForComodification(); } final void checkForComodification() { if (modCount != expectedModCount) throw new ConcurrentModificationException(); } }

增强for循环相当于在while里调用了hasnext方法以及调用了next的方法,最后调用了外部的remove方法(注意,不是内部类itr的方法,此时expectedModCount为3

调用remove方法时的源码,实质调用了fastRemove,此刻modCount又加1变为了4

复制代码
1
2
3
4
5
6
7
8
private void fastRemove(int index) { modCount++; int numMoved = size - index - 1; if (numMoved > 0) System.arraycopy(elementData, index+1, elementData, index, numMoved); elementData[--size] = null; // clear to let GC do its work }

最后

还记得上边循环调用了next方法吗,我们来看一下next方法

复制代码
1
2
3
4
5
6
7
8
9
10
11
public E next() { checkForComodification(); 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]; }

里边有个checkForComodification()

复制代码
1
2
3
4
final void checkForComodification() { if (modCount != expectedModCount) throw new ConcurrentModificationException(); }

而此刻modCount为4,expectedModCount为3,不相等,所以抛出异常。

解决方案

我们注意到,在Itr内部类中有个remove方法,其中有个代码让expectedModCount=modCount(代码注释标出)

复制代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
public void remove() { if (lastRet < 0) throw new IllegalStateException(); checkForComodification(); try { ArrayList.this.remove(lastRet); cursor = lastRet; lastRet = -1; expectedModCount = modCount; //是这个代码 } catch (IndexOutOfBoundsException ex) { throw new ConcurrentModificationException(); } }

所以我们需要调用内部类里边的remove。标准代码如下:

复制代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
@Test public void doSomething(){ ArrayList<String> list = new ArrayList<String>(); list.add("昨天"); list.add("今天"); list.add("明天"); Iterator<String> iterator = list.iterator(); while (iterator.hasNext()){ if (iterator.next().equals("昨天")){ iterator.remove(); } } System.out.println(list); }

扩充

这种机制成为“fail-fast”机制,也就是只要出现一个异常,程序及时止损不再往下运行。这种机制一般仅用于检测bug。

OK,今天也是一知半解的一天,如果对你有帮助,赶紧点赞收藏关注。

最后

以上就是会撒娇衬衫最近收集整理的关于为什么不建议用增强for循环删除列表中元素(通俗易懂版)分析然后最后解决方案扩充的全部内容,更多相关为什么不建议用增强for循环删除列表中元素(通俗易懂版)分析然后最后解决方案扩充内容请搜索靠谱客的其他文章。

本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
点赞(65)

评论列表共有 0 条评论

立即
投稿
返回
顶部