`

遍历集合删除元素

阅读更多
一、根据下标删除元素

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 来进行集合删除的操作。
分享到:
评论

相关推荐

    C#遍历List并删除某个元素的方法

    当我们需要遍历List并根据条件删除特定元素时,需要注意正确的方法,以避免在遍历过程中出现错误。以下将详细介绍如何在C#中遍历List并删除元素,包括正序和倒序遍历的技巧。 首先,我们来看一下错误的遍历方式。...

    使用Iterator接口遍历集合元素

    使用 Iterator 接口遍历集合元素 Java 集合框架中的 Iterator 接口是一种非常重要的接口,它主要用于遍历集合中的元素。Iterator 接口隐藏了各种 Collection 实现类的底层细节,向应用程序提供了遍历 Collection ...

    C#在foreach遍历删除集合中元素的三种实现方法

    在foreach中删除元素时,每一次删除都会导致集合的大小和元素索引值发生变化,从而导致在foreach中删除元素时会抛出异常。 集合已修改;可能无法执行枚举操作。 方法一:采用for循环,并且从尾到头遍历 如果...

    65丨迭代器模式(上):相比直接遍历集合数据,使用迭代器有哪些优势?1

    迭代器模式是一种行为设计模式,主要目的是在不暴露集合内部结构的情况下,允许外部代码遍历集合的所有元素。这种模式将遍历操作从集合类中分离出来,实现了数据结构和遍历机制的解耦。在大多数编程语言中,迭代器...

    java 使用foreach遍历集合元素的实例

    在Java编程语言中,`foreach`循环是一种简洁的遍历集合元素的方式,它引入自Java 5(JDK 1.5)。`foreach`循环也被称为增强for循环,它的主要目的是简化对数组和集合的迭代操作。在本实例中,我们将深入探讨如何使用...

    66丨迭代器模式(中):遍历集合的同时,为什么不能增删集合元素?1

    总的来说,迭代器模式在遍历集合时提供了一种优雅的方式,但同时也要求我们在遍历过程中谨慎处理对集合的修改。正确使用迭代器提供的方法,如`Iterator.remove()`,可以确保遍历的正确性和一致性。同时,了解不同...

    C#遍历集合与移除元素的方法

    在C#编程中,遍历集合和移除元素是常见的操作,尤其在处理大量数据时。本篇文章将详细讲解如何使用C#有效地遍历集合并安全地移除元素,同时提供一些最佳实践。 首先,我们要了解C#中的两种主要遍历集合的方式:`for...

    java中循环遍历删除List和Set集合中元素的方法(推荐)

    在Java编程中,遍历并删除集合(如List或Set)中的元素是一项常见的操作,但如果不正确地执行,可能会...在遍历集合时,始终优先考虑使用Iterator或Java 8以上的特性,以避免`ConcurrentModificationException`异常。

    Java遍历集合方法分析(实现原理、算法性能、适用场合)_.docx

    本文将深入分析Java中三种主要的遍历集合方法:传统的for循环遍历、迭代器遍历以及foreach循环遍历。 1. **传统的for循环遍历**: 这种方式依赖于计数器,开发者需要手动初始化并维护计数器,依次读取集合中的每个...

    .遍历DOM元素

    1. 操作DOM:遍历DOM可以方便地查找特定节点,添加、删除或修改元素。 2. 渲染动画:遍历DOM可以实现复杂的动画效果,比如逐个改变元素样式。 3. 数据绑定:在MVVM框架中,遍历DOM用于将数据绑定到视图。 4. 事件...

    Java遍历集合的三种方式

    本文将详细介绍Java中遍历集合的三种常见方式,并通过实例进行对比分析。 ### 方式一:转化为数组后遍历 这种方式首先将集合(如List)转化为数组,然后通过数组的for-each循环进行遍历。代码如下: ```java ...

    HashMap和List遍历方法及如何遍历删除元素总结

    HashMap和List遍历方法及如何遍历删除元素总结 HashMap和List都是Java中最常用的数据结构,它们都可以用来存储和操作数据。然而,在遍历和删除元素时,需要小心地处理,以免出现问题。下面总结了HashMap和List的...

    C#集合遍历时删除和增加元素的方法

    当我们需要在遍历集合的过程中删除或添加元素时,必须注意一些特定的策略,因为不是所有的集合类型都支持这种操作。这里我们将详细讨论如何在C#中处理这种情况,特别是在使用`LinkedList&lt;T&gt;`时。 首先,C#的标准...

    使用Enumeration和Iterator遍历集合类详解

    接下来,我们将深入探讨这两个接口,以及它们在遍历集合时的差异和应用场景。 首先,`Enumeration` 是早期Java版本(JDK 1.0)中引入的接口,主要用于遍历 `Vector`、`Hashtable` 等旧版集合类。`Enumeration` 提供...

    遍历并批量删除容器中元素出现ConcurrentModificationException原因及处置

    当你在一个迭代器正在遍历集合的过程中添加或删除元素时,就会抛出这个异常。这个问题在单线程环境下不会出现,但在多线程并发场景下,如果多个线程同时修改一个集合,就可能导致`ConcurrentModificationException`...

    Java遍历集合方法分析(实现原理、算法性能、适用场合)

    在Java中,常见的遍历集合的方法包括传统的for循环、迭代器Iterator以及foreach循环。 1. 传统的for循环遍历 这种方式需要开发者手动维护一个计数器,并通过调用`size()`方法获取集合长度,然后通过`get(index)`...

    java遍历list集合.zip

    Java中的List接口定义了iterator()方法,返回一个Iterator对象,用于遍历集合。使用迭代器的优点是可以安全地删除集合中的元素,而不会影响到其他元素的索引。 ```java List&lt;String&gt; list = new ArrayList(); // ...

    正确遍历删除List中的元素方法(推荐)

    - **推荐**:使用Iterator是安全的遍历和删除元素的方法,因为它允许在遍历过程中修改底层集合。 - **示例**: ```java Iterator&lt;Student&gt; stuIter = students.iterator(); while (stuIter.hasNext()) { ...

Global site tag (gtag.js) - Google Analytics