List删除元素()
来源:互联网 发布:英国皇家芭蕾舞团 知乎 编辑:程序博客网 时间:2024/05/21 13:52
应用中可能会遇到这种情况,需要比较List中的元素是否满足一定的条件,如果满足条件需要把这个元素从List中删除或是在这个元素前添加一个元素等等。
现在有一个ArrayList我要里面放置了几个字母[A, B, C,C ,D, E, F]
现在我要删除所有的C,于是乎我手速飞快的敲下了以下几行代码
for(int i = 0; i < list.size(); i++){ if("C".equals(list.get(i))){ list.remove(i); } }
看下输出
原始list===[A, B, C, C, D, E, F]删除C后的===[A, B, C, D, E, F]
原因是第一次元素为C时i为2,然后第一个C被删除,后边所有元素下标都向前进,于是第二个C的下标也变成了2,但这时i已经变为3了,所以第二个C不会被遍历到,于是就没有被删除。解决方法是每次删除成功i–
如果使用foreach遍历删除也有坑,回报java.util.ConcurrentModificationException
for (String string : list) { if("C".equals(string)){ list.remove("C"); } }
来看一下为什么回报这个异常,对于集合foreach这种遍历方式其实用的就是迭代器遍历,和下面这种写法没有区别
Iterator<String> it = list.iterator(); while(it.hasNext()){ if("C".equals(it.next())){ list.remove("C"); } }
来看下这是个什么异常,JDK8,在ArrayList中找到iterator()方法
public Iterator<E> iterator() { return new 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; 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(); } }
Itr类是ArrayList的内部类,类里面有三个属性
cursor 下一个元素下标
lastRet 最近遍历的元素下标
expectedModCount 期待修改次数
初始化期待修改次数为modCount,modCount记录了实际修改次数当调用ArrayList的remove方法时modCount+1
public E remove(int index) { rangeCheck(index); modCount++; E oldValue = elementData(index); 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 return oldValue; }
因为迭代器每次next()会调用checkForComodification()
final void checkForComodification() { if (modCount != expectedModCount) throw new ConcurrentModificationException(); }
因为只修改了modCount所以现在他和expectedModCount不相等,于是抛出异常。
解决这个问题的方法是使用迭代器的remove方法
Iterator<String> it = list.iterator(); while(it.hasNext()){ if("C".equals(it.next())){ it.remove(); } }
在上面的迭代器的remove()方法里面有
expectedModCount = modCount;
同步期望修改次数和实际修改次数,这样下次检查时他俩相等就不会报错。
但是上边的方法在多线程的情况下也会报 java.util.ConcurrentModificationException
Thread thread = new Thread(new Runnable() { @Override public void run() { Iterator<String> it1 = list.iterator(); while(it1.hasNext()){ try { Thread.sleep(100L); if("C".equals(it1.next())){ it1.remove(); } } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } } } }); Thread thread2 = new Thread(new Runnable() { @Override public void run() { Iterator<String> it1 = list.iterator(); while(it1.hasNext()){ try { Thread.sleep(50); if("C".equals(it1.next())){ it1.remove(); } } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } } } }); thread.start(); thread2.start();
这是为什么呢?因为modCount是AbstractList中的变量,多个迭代器对list进行remove时只把自己的expectedModCount和modCount同步了,但是并没有通知其他的迭代器去同步。结果就导致一个迭代器删除某个元素,modCount值也变了,当另一个迭代器next()检查expectedModCount和modCount不相同,于是报错。那么通过吧ArrayList换成Vector呢?结果是依然报错。
public void remove() { if (lastRet == -1) throw new IllegalStateException(); synchronized (Vector.this) { checkForComodification(); Vector.this.remove(lastRet); expectedModCount = modCount; } cursor = lastRet; lastRet = -1; }
因为Vector在这了上的锁,会发生什么情况呢?当一个迭代器删除元素时别的迭代器都不能去删除这个元素,但是删除完了呢?迭代器只是同步了自己的expectedModCount,别的迭代器和当前的modCount依然不同。
多线程解决的办法是用CopyOnWriteArrayList
———————————-我是分隔线—————————————————————-
同事说可以用Collections的synchronizedList方法包装一下list,试了一些,仍然对于迭代器的操作仍然是线程不安全的。
具体的可以看这篇博客
http://blog.csdn.net/yangzl2008/article/details/39456817
- List 删除指定元素
- list删除元素
- STL删除list元素
- List集合删除元素
- list删除元素
- List删除重复元素
- list删除元素问题
- list列表删除元素
- python删除list元素
- Python List 删除元素
- 从list删除元素
- 删除list中元素
- 遍历List,删除元素
- List删除元素
- list删除元素
- 删除List中的元素
- List删除元素()
- 删除List中指定元素
- 表单提交乱码
- Python与机器学习(二) Pandas库
- psc
- 拦截器和文件上传
- 可迁移数据库的基本命名和实施规范
- List删除元素()
- Google Cloud Platform 学习笔记(二)
- erlang eep库(未学习)
- Hadoop NodeManager无法启动问题解决
- Redis 简介
- jstat命令查看jvm的GC情况 (以Linux为例)
- Git-解释“Swap file .MERGE_MSG.swp already exists”的问题
- JAVASCRIPT第一天学习
- bzoj2083 [POI2004]PRZ 状压DP