List 循环遍历中删除元素问题二

版权声明:转载请标明出处 https://blog.csdn.net/weixin_36759405/article/details/83904452

问题一可以看我之前写的博客List 循环遍历中删除元素问题一

问题二主要讲的是博主在今天的开发中遇到的一个问题,先来看下是什么问题让博主继上次问题后又写了问题二。

问题一中讲到通过Iterator的remove方法解决链表中循环删除元素的问题。来看下简单的代码:

public class ListTest {

    public static void main(String[] args) {
        List<String> list = new ArrayList<>();
        list.add("1");
        list.add("2");
        list.add("3");
        list.add("4");
        list.add("5");

        Iterator<String> iterator = list.iterator();
        while (iterator.hasNext()) {
            String s = iterator.next();
            if ("4".equals(s)) {
                iterator.remove();
            }
        }

        System.out.println("list:" + list);
    }
}

输出:list:[1, 2, 3, 5],成功删除元素4。

但是这种解决方法中隐藏着一个坑。在今天和前端的联调过程中发现,我们一般从数据库查询多条数据时会返回List<?>,?表示具体的实体类,然后通过Iterator遍历List删除其中的元素,以下是类似的代码:

public class ListTest {

    public static void main(String[] args) {
        List<String> list = Arrays.asList("1","2","3","4","5");
        
        Iterator<String> iterator = list.iterator();
        while (iterator.hasNext()) {
            String s = iterator.next();
            if ("4".equals(s)) {
                iterator.remove();
            }
        }

        System.out.println("list:" + list);
    }
}

原本以为通过iterator.remove()方法能够成功删除元素,但是上述代码在控制台却报了这么一个错:

Exception in thread "main" java.lang.UnsupportedOperationException
	at java.util.AbstractList.remove(AbstractList.java:161)
	at java.util.AbstractList$Itr.remove(AbstractList.java:374)
	at list.ListTest.main(ListTest.java:22)

一开始感到很困惑,但是在经过自己debug之后终于发现了问题所在,debug下进入的第一个方法:

public void remove() {
    if (lastRet < 0)
        throw new IllegalStateException();
    checkForComodification();

    try {
        AbstractList.this.remove(lastRet);
        if (lastRet < cursor)
            cursor--;
        lastRet = -1;
        expectedModCount = modCount;
    } catch (IndexOutOfBoundsException e) {
        throw new ConcurrentModificationException();
    }
}

在执行到AbstractList.this.remove(lastRet);时进入下一个方法:

public abstract class AbstractList<E> extends AbstractCollection<E> implements List<E> {
    
    /*... 其它方法略...*/

	public E remove(int index) {
	    throw new UnsupportedOperationException();
	}
}

原来此处的ArrayList是一个实现了AbstractList的内部类,并且没有覆盖add和remove方法,默认这2个方法是会直接报“UnsupportedOperationException”的。

知道问题原因后,解决方法也就明确了。

public class ListTest {

    public static void main(String[] args) {
        List<String> list = Arrays.asList("1","2","3","4","5");

        List<String> result= new ArrayList<>(list);
        Iterator<String> iterator = result.iterator();
        while (iterator.hasNext()) {
            String s = iterator.next();
            if ("4".equals(s)) {
                iterator.remove();
            }
        }

        System.out.println("list:" + result);
    }
}

通过将list拷贝到一个新的ArrayList中即可解决问题二。

总结:在设计一个对外方法的时候,一点要谨慎处理集合和数组。因为你永远不知道传给你的集合是什么,也不知道是否会有对此集合有任何其他的不可控的操作。所以在使用客户端传递的集合对象时,最好拷贝一个新集合后再操作。

猜你喜欢

转载自blog.csdn.net/weixin_36759405/article/details/83904452