近期面试遇到这样一个问题
List能在遍历的时候删除元素吗?
当时思考的使用普通或者增强for循环肯定会出问题,于是回答可以使用iterator迭代器进行删除。
又问实际开发过程中,你直接写一个迭代器吗?
对啊...相视无言
昨天一朋友跟我说他code review的时候,组长说他写的迭代器代码臃肿、恶心、low...
突然想到jdk1.8之后的新特性lambda表达式和stream流(高端大气上档次)
完全可以用,下面附上几种方式对比以及存在的问题:
1.普通for遍历
List<String> list = new ArrayList();
list.add("1");
list.add("2a");
list.add("2b");
list.add("2c");
list.add("2d");
for (int i = 0; i < list.size(); i++) {
if (list.get(i).startsWith("2")){
list.remove(i);
}
}
//sout[1, 2b, 2d]
删除某个元素之后,list集合发生变化,数据前移,"2a"索引为"1",删除之后后边的数据前移一位,但此时"1"索引已经遍历过了,会直接访问"2"索引即"2c",删掉"2c"后依旧存在相同问题,漏删"2d",存在严重的漏删问题。
2.增强for遍历(foreach)
List<String> list = new ArrayList();
list.add("1");
list.add("2a");
list.add("2b");
list.add("2c");
list.add("2d");
for (String s : list) {
if (s.startsWith("2")){
list.remove(s);
}
}
//Exception in thread "main" java.util.ConcurrentModificationException
直接报ConcurrentModificationException,由于增强for底层用的是iterator迭代器,如果了解源码的话就会发现iterator的next和remove方法都调用了checkForComodifcation方法(点进去看源码)
这个方法会判断modCount(集合修改次数)与expectedModCount(迭代器修改次数)是否相等,如果不相等,就会抛出异常。
而使用迭代器的删除方法就不会出现异常
3.iterator迭代器
使用迭代器remove方法,会同步两个修改次数,不会报异常,
List<String> list = new ArrayList();
list.add("1");
list.add("2a");
list.add("2b");
list.add("2c");
list.add("2d");
Iterator<String> iterator = list.iterator();
while (iterator.hasNext()){
if (iterator.next().startsWith("2")){
iterator.remove();
}
}
//sout:[1]
4.lambda表达式
stream流式编程,利用一个简单的过滤.filter
List<String> list = new ArrayList();
list.add("1");
list.add("2a");
list.add("2b");
list.add("2c");
list.add("2d");
list = list.stream()
.filter(str->!str.startsWith("2"))
.collect(Collectors.toList());
//[1]