目录
1、直接使用普通for 循环进行操作
我们说不能在foreach 中进行,但是使用普通的for 循环还是可以的,因为普通for
循环并没有用到Iterator 的遍历,所以压根就没有进行fail-fast 的检验。
List<String> userNames = new ArrayList<String>() {{
add("Hollis");
add("hollis");
add("HollisChuang");
add("H");
}};
for (int i = 0; i < 1; i++) {
if (userNames.get(i).equals("Hollis")) {
userNames.remove(i);
}
}
System.out.println(userNames);
这种方案其实存在一个问题,那就是remove 操作会改变List 中元素的下标,可能存
在漏删的情况。
2、直接使用Iterator 进行操作
除了直接使用普通for 循环以外,我们还可以直接使用Iterator 提供的remove 方法。
List<String> userNames = new ArrayList<String>() {{
add("Hollis");
add("hollis");
add("HollisChuang");
add("H");
}};
Iterator iterator = userNames.iterator();
while (iterator.hasNext()) {
if (iterator.next().equals("Hollis")) {
iterator.remove();
}
}
System.out.println(userNames);
集合类< 194
如果直接使用I t e r a t o r 提供的r e m o v e 方法, 那么就可以修改到
expectedModCount 的值。那么就不会再抛出异常了。
3、使用Java 8 中提供的filter 过滤
Java 8 中可以把集合转换成流,对于流有一种filter 操作, 可以对原始Stream 进
行某项测试,通过测试的元素被留下来生成一个新Stream。
List<String> userNames = new ArrayList<String>() {{
add("Hollis");
add("hollis");
add("HollisChuang");
add("H");
}};
userNames = userNames.stream().filter(userName -> !userName.equals("Hol
lis")).collect(Collectors.toList());
System.out.println(userNames);
4、使用增强for 循环其实也可以
如果,我们非常确定在一个集合中,某个即将删除的元素只包含一个的话, 比如对
Set 进行操作,那么其实也是可以使用增强for 循环的,只要在删除之后,立刻结束循环体,
不要再继续进行遍历就可以了,也就是说不让代码执行到下一次的next 方法。
List<String> userNames = new ArrayList<String>() {{
add("Hollis");
add("hollis");
add("HollisChuang");
add("H");
}};
for (String userName : userNames) {
if (userName.equals("Hollis")) {
userNames.remove(userName);
break;
}
}
System.out.println(userNames);
195 > 集合类
5、直接使用fail-safe 的集合类
在Java 中,除了一些普通的集合类以外,还有一些采用了fail-safe 机制的集合类。
这样的集合容器在遍历时不是直接在集合内容上访问的,而是先复制原有集合内容,在拷贝
的集合上进行遍历。
由于迭代时是对原集合的拷贝进行遍历,所以在遍历过程中对原集合所作的修改并不能
被迭代器检测到,所以不会触发ConcurrentModificationException。
ConcurrentLinkedDeque<String> userNames = new ConcurrentLinkedDeque<String>
() {{
add("Hollis");
add("hollis");
add("HollisChuang");
add("H");
}};
for (String userName : userNames) {
if (userName.equals("Hollis")) {
userNames.remove();
}
}
基于拷贝内容的优点是避免了ConcurrentModificationException,但同样地,迭代
器并不能访问到修改后的内容,即:迭代器遍历的是开始遍历那一刻拿到的集合拷贝,在遍
历期间原集合发生的修改迭代器是不知道的。
java.util.concurrent 包下的容器都是安全失败,可以在多线程下并发使用,并发修改。