3种不同的遍历问题
【强制】不要在foreach循环里进行元素的remove/add操作。remove元素请使用Iterator方式,如果并发操作,需要对Iterator对象加锁。
Iterator
-
对 collection 进行迭代的迭代器。迭代器取代了 Java Collections Framework 中的 Enumeration。迭代器与枚举有两点不同:
- ==迭代器允许调用者利用定义良好的语义在迭代期间从迭代器所指向的== collection ==移除元素==。
- 方法名称得到了改进。
此接口是 Java Collections Framework 的成员。
-
collection实现了Iterator()方法,所有集合类都能使用集合类
方法摘要 boolean
hasNext()
如果仍有元素可以迭代,则返回true
。E
next()
返回迭代的下一个元素。void
remove()
==从迭代器指向的 collection 中移除迭代器返回的最后一个元素==(可选操作)。
public interface Iterator<E>
该接口是迭代器底层是通过指针的挪动来遍历集合元素
遍历期间不能进行增删原集合内容
Iterable接口(Collection的父接口)里定义了可以返回Iterator接口的方法iterator()
-
public interface Iterable<T>
实现这个接口允许对象成为 "foreach" 语句的目标。
-
只要某个类实现了Iterable接口,这个类就可以被增强for循环(foreach)遍历
- ==增强for循环的底层是通过迭代器实现。==
- 遍历期间无法对集合里的元素进行操作
- 增强for循环是JDK1.5的新特性
-
-
Iterator遍历删除原理:根据根据在遍历期间改变标记值来间接删除集合元素(这是基于JDK1.8之前的版本解释)
- 先==复制==一个集合,并且每个元素标记true
- 调用remove()方法会将true改成false
- 再遍历结束,会将标记值与原来集合比较,标记为false的会自动删除
- 如果期间集合元素和原来不同会产生异常ConcurrentModificationException
- 不能对原集合直接增删-----遍历期间改变原集合,遍历结束会根据标记值和原集合进行状态的对比
Iterator<String> iterator = v.iterator(); while(iterator.hasNext()){ String next = iterator.next(); //通过迭代器的对象删除遍历已经获取的元素 /* - 先复制一个集合,并且每个元素标记true 调用remove()方法会将true改成false 再遍历结束,会将标记值与原来集合比较,标记为false的会自动删除*/ //iterator.remove(); //通过集合对象删除 //会删除直接原集合元素 //遍历结束,比较标记值,与原来内容不同产生异常 v.remove(next); //ConcurrentModificationException System.out.print(next); }
- foreach:因为foreach的底层也是iterator,而且没有iterator中的remove()方法,所以无法直接对集合里的元素进行删除。
-
1.原始的for循环删除集合元素的时候有可能会漏掉某个元素
测试代码:/** - 假设需要删除集合中的所有的"A"元素 - 如果使用原始的for循环,那么就可能会漏删 */ List<String> list = new ArrayList<>(); list.add("A"); list.add("A"); list.add("B"); for(int i=0; i<list.size(); i++) { if("A".equals(list.get(i))) { list.remove(i); } } System.out.println(list);
输出结果:
[A, B]
可以看到集合中只有一个"A"被删了,第二个"A"却还在。其实解决办法也很简单,在删除元素之后再加一行代码i--就解决了
- 题外:Vector中有elements()方法,存在最古老的迭代器Enumeration
//用于遍历,返回最古老的迭代器 ,只存在于Voctor,原码
public Enumeration<E> elements() {
return new Enumeration<E>() {
int count = 0;
public boolean hasMoreElements() { //放在while循环,判断是否还有元素
return count < elementCount;
}
public E nextElement() { //用于获取元素
synchronized (Vector.this) {
if (count < elementCount) {
return elementData(count++);
}
}
throw new NoSuchElementException("Vector Enumeration");
}
};
}
/* //调用Elements方法返回迭代器,测试
//会默认把Vector对象身上所有元素放到迭代器上
Enumeration<String> elements = v.elements();
//迭代遍历
while(elements.hasMoreElements()){//判断是否还有元素
//获取元素
String str = elements.nextElement();
System.out.print(str);
}
*/