遍历集合删除元素
程序员文章站
2022-05-02 09:49:37
...
一、根据下标删除元素
1.测试代码
2.实现原理
3.其他情况
删除单个元素,可以使用此方式,但多个元素的情况下不可以
因为删除一个元素后,数组的大小以及原来元素的下标都会改变;需要做相应的处理才可。
二、foreach
1.代码实现
运行抛出异常
Exception in thread "main" java.util.ConcurrentModificationException
at java.util.ArrayList$Itr.checkForComodification(ArrayList.java:859)
at java.util.ArrayList$Itr.next(ArrayList.java:831)
2.异常分析
从定位的异常信息看遍历的过程中进行了 chcek
modCount 实际对数组进行操作的次数,expectedModCount 预期操作次数
初始化
但在遍历的同时,执行了remove操作,导致了 modCount+1 ,与 expectedModCount 不一致
3.为什么删除元素的方法会调用 Next
java foreach 实现原理
中 foreach 实质就是Iterator 的调用实现
删除元素的实现过程
即可以认为调用了 ArrayList 的 Iterator 方法,返回了 其内部实现的静态类 Itr
在foreach 的过程中,即 Iterator 的 next 操作的过程中 每次获取下一个元素前都会进行一次校验
抛出不允许同时进行修改操作的异常
三、Iterator
将集合转为Iterator 通过 Iterator 来进行集合删除的操作。
1.测试代码
ArrayList<String> list = new ArrayList<String>(Arrays.asList("a", "b", "c", "d")); for(int index = 0 ; index < list.size() ; index++){ if(Objects.equals("a", list.get(index))){ list.remove(index); } } System.out.println(String.valueOf(list));
2.实现原理
/** * Removes the element at the specified position in this list. * Shifts any subsequent elements to the left (subtracts one from their * indices). * * @param index the index of the element to be removed * @return the element that was removed from the list * @throws IndexOutOfBoundsException {@inheritDoc} */ // 在列表中指定位置删除元素。 // 所有后续元素左移(下标减1)。 public E remove(int index) { rangeCheck(index); // 是否越界,index 是否大于了 数组的长度 modCount++; // 操作次数 E oldValue = elementData(index); int numMoved = size - index - 1; // 将index+1后numMoved个元素拷贝到index的位置上 // 覆盖index位置上的元素,多出的一个位置设置为null,等待GC if (numMoved > 0) System.arraycopy(elementData, index+1, elementData, index, numMoved); elementData[--size] = null; // clear to let GC do its work return oldValue; }
3.其他情况
删除单个元素,可以使用此方式,但多个元素的情况下不可以
因为删除一个元素后,数组的大小以及原来元素的下标都会改变;需要做相应的处理才可。
ArrayList<String> list1 = new ArrayList<String>(Arrays.asList("a", "b", "c", "d")); for(int index = 0 ; index < list1.size() ; index++){ // 删除 index = 0 即 a 元素后,数组大小变为3,b的下标变为0,所以再次删除的是c,最后退出循环 list1.remove(index); } System.out.println(String.valueOf(list1));
二、foreach
1.代码实现
for (String s : list) { if (s.equals("a")) list.remove(s); }
运行抛出异常
Exception in thread "main" java.util.ConcurrentModificationException
at java.util.ArrayList$Itr.checkForComodification(ArrayList.java:859)
at java.util.ArrayList$Itr.next(ArrayList.java:831)
2.异常分析
// 异常抛出的位置 final void checkForComodification() { if (modCount != expectedModCount) throw new ConcurrentModificationException(); } /** * An optimized version of AbstractList.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();// 对应的831行代码 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]; } }
从定位的异常信息看遍历的过程中进行了 chcek
final void checkForComodification() { if (modCount != expectedModCount) throw new ConcurrentModificationException(); }
modCount 实际对数组进行操作的次数,expectedModCount 预期操作次数
初始化
int expectedModCount = modCount;
但在遍历的同时,执行了remove操作,导致了 modCount+1 ,与 expectedModCount 不一致
3.为什么删除元素的方法会调用 Next
java foreach 实现原理
中 foreach 实质就是Iterator 的调用实现
/** * Returns an iterator over the elements in this list in proper sequence. * * <p>The returned iterator is <a href="#fail-fast"><i>fail-fast</i></a>. * * @return an iterator over the elements in this list in proper sequence */ public Iterator<E> iterator() { return new Itr(); } /** * An optimized version of AbstractList.Itr */ private class Itr implements Iterator<E> {}
删除元素的实现过程
public boolean remove(Object o) { if (o == null) { for (int index = 0; index < size; index++) if (elementData[index] == null) { fastRemove(index); return true; } } else { for (int index = 0; index < size; index++) if (o.equals(elementData[index])) { fastRemove(index); return true; } } return false; }
即可以认为调用了 ArrayList 的 Iterator 方法,返回了 其内部实现的静态类 Itr
在foreach 的过程中,即 Iterator 的 next 操作的过程中 每次获取下一个元素前都会进行一次校验
抛出不允许同时进行修改操作的异常
三、Iterator
Iterator<String> iterator = list.iterator(); while(iterator.hasNext()){ if(StringUtils.isNotEmpty(iterator.next())){ iterator.remove(); } }
将集合转为Iterator 通过 Iterator 来进行集合删除的操作。