zoukankan      html  css  js  c++  java
  • List删除操作

    在Java中对列表进行删除操作时,如果使用不当的话,会产生java.util.ConcurrentModificationException异常。

        @Test
        public void remove2() {
    
            // java.util.ConcurrentModificationException
    
            List<Integer> list = new ArrayList<>();
            list.add(1);
            list.add(2);
            list.add(3);
            list.add(4);
            list.add(5);
    
            for (Integer number : list) {
                if (number % 2 == 0) {
                    list.remove(number);
                }
            }
            System.out.println(Arrays.toString(list.toArray()));
        }
    

    运行上边的测试代码,产生如下异常

    java.util.ConcurrentModificationException
    	at java.util.ArrayList$Itr.checkForComodification(ArrayList.java:909)
    	at java.util.ArrayList$Itr.next(ArrayList.java:859)
    	at com.st.learning.algorithm.ListRemoveTest.remove2(ListRemoveTest.java:51)
    	at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    	at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
    	at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    	at java.lang.reflect.Method.invoke(Method.java:498)
    	at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:50)
    	at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12)
    	at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:47)
    	at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:17)
    	at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:325)
    	at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:78)
    	at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:57)
    	at org.junit.runners.ParentRunner$3.run(ParentRunner.java:290)
    	at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:71)
    	at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:288)
    	at org.junit.runners.ParentRunner.access$000(ParentRunner.java:58)
    	at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:268)
    	at org.junit.runners.ParentRunner.run(ParentRunner.java:363)
    	at org.junit.runner.JUnitCore.run(JUnitCore.java:137)
    	at com.intellij.junit4.JUnit4IdeaTestRunner.startRunnerWithArgs(JUnit4IdeaTestRunner.java:68)
    	at com.intellij.rt.execution.junit.IdeaTestRunner$Repeater.startRunnerWithArgs(IdeaTestRunner.java:47)
    	at com.intellij.rt.execution.junit.JUnitStarter.prepareStreamsAndStart(JUnitStarter.java:242)
    	at com.intellij.rt.execution.junit.JUnitStarter.main(JUnitStarter.java:70)
    

    查看生成的字节码可以看到,

    List<Integer> list = new ArrayList();
            list.add(1);
            list.add(2);
            list.add(3);
            list.add(4);
            list.add(5);
            Iterator var2 = list.iterator();
    
            while(var2.hasNext()) {
                Integer number = (Integer)var2.next();
                if (number % 2 == 0) {
                    list.remove(number);
                }
            }
    
            System.out.println(Arrays.toString(list.toArray()));
    

    foreach循环在这里使用的是Iterator实现,使用了hasNext()和next()方法。

    在ArrayList中,next()方法实现如下:

    上方标红处即为代码报错处,实现如下:

    上图中对比了modCount和expectedModCount两个字段的值,不一致时,发生了异常。

    在刚开始时,代码中的modCount和expectedModCount均为5,在执行到下方代码时,modCount发生了变化,编程了6,

    list.remove(number);
    


    这也就是问题产生的原因

    列表的删除方法

    • iterator的remove()方法
        @Test
        public void remove3() {
            List<Integer> list = new ArrayList<>();
            list.add(1);
            list.add(2);
            list.add(3);
            list.add(4);
            list.add(5);
    
            Iterator<Integer> iterator = list.iterator();
    
            while (iterator.hasNext()) {
                if (iterator.next() % 2 == 0) {
                    iterator.remove();
                }
            }
            System.out.println(Arrays.toString(list.toArray()));
        }
    


    使用iterator删除时,会将modCount的值赋值给expectedModCount,所有不会发生以上问题

  • 相关阅读:
    Redis5.x五种数据类型常见命令
    Redis5.x安装以及常见数据类型
    《Redis5.x入门教程》正式推出
    PPT制作套路指南
    如何更优雅地对接第三方API
    软件开发要质量还是要效率?
    前后端分离对于开发人员的挑战
    Spring中老生常谈的FactoryBean
    消费端如何保证消息队列MQ的有序消费
    《ElasticSearch6.x实战教程》之实战ELK日志分析系统、多数据源同步
  • 原文地址:https://www.cnblogs.com/lzw-st/p/13202136.html
Copyright © 2011-2022 走看看