List 中正确的增删操作
Posted AmoryWang_JavaSunny
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了List 中正确的增删操作相关的知识,希望对你有一定的参考价值。
这个为什么要单独说的原因是,在开发中的对数据库中的增删为最基本的,但是是不是写对了就尤为重要
先来看代码:
1 public void testLoopInList(){ 2 List<String> a = new ArrayList<String>(); 3 a.add("1"); 4 a.add("2"); 5 a.add("w"); 6 for (String string : a) { 7 System.out.println(string); 8 } 9 10 for (String temp : a) { 11 if("2".equals(temp)){ 12 a.remove(temp); 13 } 14 } 15 16 for (String string : a) { 17 System.out.println(string); 18 }
输出:
1 2 java.util.ConcurrentModificationException at java.util.ArrayList$Itr.checkForComodification(ArrayList.java:859) at java.util.ArrayList$Itr.next(ArrayList.java:831) at test.Test_ForeachAndIterator.testLoopInList(Test_ForeachAndIterator.java:19)
出现错误了
原因:首先从错误中可以看出,是ArraList中的Iterator的checkForComodification()出现的错误,说明了foreach的实现原理其实就是实现了内部类I特Iterator来进行遍历的,其次为什么会出错呢?
因为在ArrayList和ArrayList的内部类的Iterator中的都会存在remove的方法,而ArrayList和Iterator中都各自有自己的维持长度的变量,前者是modCount,后者是expectModCount,但是源码中ArrayList的remove方法是会改变modCount的值,但却不会直接同步到expectModCount的值的,而Iterator中时刻都插入了checkForComodification()方法来监测modCount是否与expectModCount相等,所以就会很容易出现异常错误,当然下面的代码也是错的
1 public void testLoopInList(){ 2 List<String> a = new ArrayList<String>(); 3 a.add("1"); 4 a.add("2"); 5 6 for (String string : a) { 7 System.out.println(string); 8 } 9 10 Iterator<String> it = a.iterator(); 11 while(it.hasNext()){ 12 if("1".equals(it.next())){ 13 a.remove(it.next()); 14 } 15 } 16 17 for (String string : a) { 18 System.out.println(string); 19 } 20 }
错误原因同上
所以在解决问题的关键就是要避免这个异常的出现,也就是时刻让modCount==expectModCount,所以就是使用iterator的remove方法,因为会有使两者相等的代码
即下面:
1 public void testLoopInList(){ 2 List<String> a = new ArrayList<String>(); 3 a.add("1"); 4 a.add("2"); 5 6 for (String string : a) { 7 System.out.println(string); 8 } 9 10 Iterator<String> it = a.iterator(); 11 while(it.hasNext()){ 12 if("1".equals(it.next())){ 13 it.remove(); 14 } 15 } 16 17 for (String string : a) { 18 System.out.println(string); 19 } 20 }
相关源码提上:
1 private class Itr implements Iterator<E> { 2 /** 3 * Index of element to be returned by subsequent call to next. 4 */ 5 int cursor = 0; 6 /** 7 * Index of element returned by most recent call to next or 8 * previous. Reset to -1 if this element is deleted by a call 9 * to remove. 10 */ 11 int lastRet = -1; 12 /** 13 * The modCount value that the iterator believes that the backing 14 * List should have. If this expectation is violated, the iterator 15 * has detected concurrent modification. 16 */ 17 int expectedModCount = modCount; 18 public boolean hasNext() { 19 return cursor != size(); 20 } 21 public E next() { 22 checkForComodification(); 23 try { 24 E next = get(cursor); 25 lastRet = cursor++; 26 return next; 27 } catch (IndexOutOfBoundsException e) { 28 checkForComodification(); 29 throw new NoSuchElementException(); 30 } 31 } 32 public void remove() { 33 if (lastRet == -1) 34 throw new IllegalStateException(); 35 checkForComodification(); 36 try { 37 AbstractList.this.remove(lastRet); 38 if (lastRet < cursor) 39 cursor--; 40 lastRet = -1; 41 expectedModCount = modCount; 42 } catch (IndexOutOfBoundsException e) { 43 throw new ConcurrentModificationException(); 44 } 45 } 46 final void checkForComodification() { 47 if (modCount != expectedModCount) 48 throw new ConcurrentModificationException(); 49 }
ArrayList中的remove
1 public boolean remove(Object o) { 2 if (o == null) { 3 for (int index = 0; index < size; index++) 4 if (elementData[index] == null) { 5 fastRemove(index); 6 return true; 7 } 8 } else { 9 for (int index = 0; index < size; index++) 10 if (o.equals(elementData[index])) { 11 fastRemove(index); 12 return true; 13 } 14 } 15 return false; 16 }
以上是关于List 中正确的增删操作的主要内容,如果未能解决你的问题,请参考以下文章