对List遍历过程中添加和删除的思考

Posted CodingBoy

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了对List遍历过程中添加和删除的思考相关的知识,希望对你有一定的参考价值。

对List遍历过程中添加和删除的思考

经过测试,发现对于一个集合,如果要在遍历的过程中,进行add或者remove操作的时候,如果操作不慎,都会导致报错。

主要错误:

  • java.util.ConcurrentModificationException 遍历过程中add/remove导致的错误

  • java.lang.IndexOutOfBoundsException 越界错误

最佳实践

add操作:利用原生的for循环。remove操作利用foreach操作。如下所示:

    //OK,利用 iterator 和 其remove 方法
   @Test
   public void testIteratorRemove2() {
       Iterator<String> iterator = list.iterator();
       while (iterator.hasNext()) {
           if ("3".equals(iterator.next())) {
               iterator.remove();
          }
      }
       System.out.println(list);
  }
?
   //OK 利用for循环。
   @Test
   public void testForAdd() {
       for (int i = 0, length = list.size(); i < length; i++) {
           if (list.get(i).equals("2")) {
               list.add("2");
          }
      }
  }

经典错误1

如下代码本意是:通过iterator的方式从头到尾变遍历list中的元素。

    @Test
   public void testIteratorRemove2() {
       while (list.iterator().hasNext()) {
         System.out.println(list.iterator().next());
      }
  }

但是该段代码永远都会输出 list的第一元素,为什么?关键错误在链式写法上:

 while (list.iterator().hasNext()) {}

每次循环时候先调用了list.iterator() 在该方法中每次都是重新new了一个新的对象


   public Iterator<E> iterator() {
       return new Itr();
  }

所以每一次都是一个新的遍历对象,所以输出第一个元素。

那么为什么每次都要new一个新的Itr()?我猜想应该是为了并发的读,每次读的都是一份独立的数据,避免多个并发读的时候,出现当前指针问题。

处理办法:将list.iteraotr() 放在外面即可,保证循环中循环的是1个对象。


   @Test
   public void testIteratorRemove2() {
       Iterator<String> iterator = list.iterator();
       while (iterator.hasNext()) {
           if ("3".equals(iterator.next())) {
               iterator.remove();
          }
      }
       System.out.println(list);
  }

 

经典错误2

    // 死循环
@Test
   public void testForAdd2() {
       for (int i = 0; i < list.size(); i++) {
           if (list.get(i).equals("3")) {
               list.add("3");
          }
      }
  }

当if条件满足的时候,该方法永远不会结束,为什么?

对于for循环 for (int i = 0; i < list.size(); i++)有3个部分,第一个部分为初始化,只执行一次。第二个部分每次都会执行,第三个部分也是每次都会执行。

上述问题的第二步会导致无限循环:因为for中每一次循环都会在list添加了一个元素,每次步进为1,内部元素也是每次都加1.

如何处理该问题: list.size()放在第一部分,第一部分只初始化一次。


   //OK 利用for循环。
   @Test
   public void testForAdd() {
       for (int i = 0, length = list.size(); i < length; i++) {
           if (list.get(i).equals("2")) {
               list.add("2");
          }
      }
  }

经典错误3

    //java.lang.IndexOutOfBoundsException: Index: 2, Size: 2
   @Test
   public void testForRemove() {
       for (int i = 0, length = list.size(); i < length; i++) {
           if (list.get(i).equals("3")) {
               list.remove("3");
          }
      }
  }

该错误在list.add("3")的时候就不会发生该错误,具体原因是什么?

以上是关于对List遍历过程中添加和删除的思考的主要内容,如果未能解决你的问题,请参考以下文章

集合遍历过程iterator, 添加删除元素报异常

遍历std::list过程中删除元素后继续遍历过程

List集合在遍历过程中的删除

黑马基础阶段测试题:创建一个存储字符串的集合list,向list中添加以下字符串:”C++””Java”” Python””大数据与云计算”。遍历集合,将长度小于5的字符串从集合中删除,删除成功(代码

201621123057 《Java程序设计》第9周学习总结

Java遍历List的时候删除item