对于Java中的集合类型,我们主要有两种迭代方式:
Set<String> students = new HashSet<String>(Arrays.asList("Bob","Andy","Tony"));
for (String student : students) {
System.out.println(student);
}
Iterator<String> it = students.iterator();
while(it.hasNext()) {
System.out.println(it.next());
}
假如我们想要在迭代过程中移除某些元素,举例来说,我们移除集合中包含字符’o’的字符串,我们进行如下操作:
for (String student : students) {
if (student.indexOf('o') != -1) {
students.remove(student);
}
}
或者
Iterator<String> it = students.iterator();
while (it.hasNext()) {
String temp = it.next();
if (temp.indexOf('o') != -1) {
students.remove(temp);
}
}
控制台输出了异常:java.util.ConcurrentModificationException,这个异常在集合迭代过程中修改集合元素引起的。Sun的Java教程这样说道:“请注意,Iterator.remove是在迭代过程中修改集合的唯一安全方法;如果在迭代过程中以任何其他方式修改了底层集合,则行为未指定。”
我们需要搞懂异常的原因:
Iterator初始化时用expectedModCount记录集合的modCount变量,此后在必要的地方它会检测modCount的值:
final void checkForComodification() {
if (modCount != expectedModCount)
throw new ConcurrentModificationException();
}
如果modCount与一开始记录在expectedModeCount中的值不等,说明集合内容被修改过,此时会抛出ConcurrentModificationException。
(来自http://blog.sina.com.cn/s/blog_60cc33d70100omhm.html)
另外,我们需要搞懂foreach的具体实现,下面的图说明了对于数组类型,foreach实际上使用的是下标遍历,对于集合类型,使用的是迭代器实现
(来自https://www.cnblogs.com/slwenyi/p/6393366.html)
现在我们知道了,上述两种方法实际上是一样的。因此,如果我们想要在迭代过程中删除某些元素,官方唯一指定方法是使用迭代器的remove方法,而不是集合本身的remove方法:
Iterator<String> it = students.iterator();
while (it.hasNext()) {
if (it.next().indexOf('o') != -1) {
it.remove();
}
}
此外,假如我们假如只需要删除一个元素,可以使用下面的方法,同样不会报错:
for (String student : students) {
if(student.indexOf('o') != -1) {
students.remove(student);
break;//在删除元素后立即退出迭代
}
}
那么,如果是添加元素的情况呢?除了只添加一次并立即退出迭代之外,集合并没有提供给我们用于添加元素的方法,因此我们只能自己想办法。常用的方法是使用另一个集合记录需要添加的元素,在迭代结束之后添加到原来的集合中。
Set<String> students = new HashSet<String>(Arrays.asList("Bob", "Andy", "Tony"));
Set<String> toAdd = new HashSet<String>();
for (String student : students) {
if(student.indexOf('o') != -1) {
toAdd.add(student + "-add");
}
}
students.addAll(toAdd);//迭代结束后添加
System.out.println(students.toString());
//输出结果:[Tony-add, Tony, Bob, Bob-add, Andy]