迭代器删除集合中的元素

刚开始接触遇到一个基础问题:在for循环中删除元素。抛出的异常是"java.util.ConcurrentModificationException"。

此处梳理总结一下:

  1、模拟异常

 1 @Test
 2 public void testException() {
 3         List<String> list = new ArrayList<>();
 4         list.add("a");
 5         list.add("b");
 6         list.add("c");
 7         list.add("d");
 8         list.add("e");
 9         for (String str : list) {// 当第一个元素被删除后,此处会抛出异常
10             if ("c".equals(str)) {
11                 list.remove("c");
12          }
13      }
14  }

  执行后抛出异常:

      java.util.ConcurrentModificationException
      at java.util.ArrayList$Itr.checkForComodification(ArrayList.java:901)
      at java.util.ArrayList$Itr.next(ArrayList.java:851)
      at sometest.loop.IteratorDemo.testException(IteratorDemo.java:69)
      at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)

  2、解决上面异常的方法 可以用迭代器iterator :  

 1 public static void main(String[] args) {
 2         List<String> list = new ArrayList<>();
 3         list.add("a");
 4         list.add("b");
 5         list.add("c");
 6         list.add("d");
 7         list.add("e");
 8         // 使用迭代器实现删除元素
 9         Iterator<String> it = list.iterator();
10         while (it.hasNext()) { // 调用hasNext方法判断是否有元素
11             if ("c".equals(it.next())) { // 获取当前元素
12                 // 因为使用迭代器的remove方法,指针会同时减一 即就不会因为出现集合的元素和指针数不等抛出异常的问题
13                 it.remove();
14             }
15         }17         list.forEach(s -> System.out.println(s));
18     }

  执行后输出结果:

            a
            b
            d
            e

  3、除了iterator还可以使用ListIIterator进行遍历删除。两者之间的区别在后续介绍。

 1 @Test
 2 public void testListIterator() {
 3         List<String> list = new ArrayList<>();
 4         list.add("a");
 5         list.add("b");
 6         ListIterator<String> it = list.listIterator();
 7         while (it.hasNext()) { // 调用hasNext方法判断是否有元素
 8             // 通过下面两种方法可以得到当前元素的索引位置
 9             System.out.println("当前元素是:" + it.next());
10             System.out.println("下一个元素的索引:" + it.nextIndex());
11             System.out.println("上一个元素的索引:" + it.previousIndex());
12         }
13         // listIterator有add()方法
14         it.add("ff");
15         list.forEach(s -> System.out.println(s));
16 }

  执行后输出结果:        

      当前元素是:a
      下一个元素的索引:1
      上一个元素的索引:0
      当前元素是:b
      下一个元素的索引:2
      上一个元素的索引:1
      遍历后元素输出:
              a
              b
              ff

  集合的iterator和ListIterator的区别:

    凡是实现类Collection接口的集合类,都有一个Iterator方法,用于返回一个实现了Iterator接口的对象,用于集合遍历;(iterator接口定义了3个方法分别是hasNext(),next(),remove())

    我们在使用集合List和Set的时候,为了实现对其数据的遍历,我们经常使用到了Iterator。在使用过程中不需要干涉其遍历过程,只需要每次取出一个你想要的的数据进行处理就可以了。

  但是在有的时候使用也是有不同的。List和Set都有iterator()来取得迭代器。对于List来说,你也可以通过listIterator()取得迭代器,两种迭代器在有些时候是不能通用的,iterator和ListIterator

  的区别主要是以下方面:

    1.  iterator()方法在set和List接口中都有定义,但是ListIterator()仅存在于list接口中 (或实现类中);

    2.  ListIterator有add()方法,可以向List中添加对象,而Iterator不能。

    3.  ListIterator有Iterator都有的hasNext()和next()方法,可以实现顺序向后遍历,但是ListIterator有hasPrevious()方法和previous方法,可以实现逆向(顺序向前)遍历。Iterator就不可以。

    4.  ListIterator可以定位当前的索引位置,nextIndex()和previousIndex()可以实现。Iterator没有此功能。

    5.  都可实现删除对象,但是ListIterator可以实现对对象的修改(set方法可以实现) Iterator没有此功能。

    因为ListIterator的这些功能,可以实现对LinkedList等List数据结构的操作。其实,数组对象也可以用迭代器来实现。

 

  因为java8的引入可以在删除元素的时候有了更简便的方法:

    从JDK1.8开始,可以使用removeIf()方法来代替 Iterator的remove()方法实现一边遍历一边删除。

 1 @Test
 2 public void testJava8RemoveIf() {
 3         List<String> list = new ArrayList<>();
 4         list.add("a");
 5         list.add("b");
 6         list.add("c");
 7         list.add("d");
 8         list.add("e");
 9         list.removeIf(s->"c".equals(s));
10         list.forEach(s-> System.out.print(s + " "));
11 }

  输出结果:

    a b d e 

posted @ 2020-07-09 17:31  竹秋千道  阅读(1558)  评论(0编辑  收藏  举报