刚开始接触遇到一个基础问题:在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