我正在参加「掘金·启航计划」
最近在做需求时,遇到了一个关于迭代器的问题,以前迭代器用的少,没怎么注意过,这次用了一下迭代器,还用出错了,感觉很有意思,记录一下......
报错
在改完代码后,前端发起请求后,后端控制台报了java.lang.IllegalStateException:null的错误:不合法的状态异常。一开始还摸不清哪里出了问题,百度了一下,才知道是我的迭代器用法出了问题。
举例
在讲述报错原因之前,先看一个例子,由这个例子引出原因:
it = newList.iterator();
while (it.hasNext()) {
FileNoUploadDto dto = it.next();
for (int i = 0; i < fileUploadDtos.size(); i++) {
it.remove(); //第一次 remove
break;
}
if (StringUtil.isEmptyList(resultDateList) || !resultDateList.contains(dto.getValDate())) {
it.remove(); //第二次 remove
}
}
这段代码中,第一次 remove 是为了过滤掉已经上传过的记录;而在 for 循环外,第二次 remove 是为了在该日期没有时,去掉该日期。这两种情况是可能同时出现的,也就是说这两次 remove 是可能同时执行的,这时,注意:当 Iterator 执行 remove 方法时,如果迭代器尚未调用 next 方法,或者在上一次调用 next 方法之后已经调用了 remove 方法,那么再次调用 remove 方法时就会抛出上述异常!
从上面的例子中可以看出,我在第一次 remove 方法前,是调用了一次 it.next() 方法的;但在第二次 remove 方法之前,没有再调用 .next() 方法了,如果两次 remove 同时执行的话,相当于总共就只有一个 .next() 方法作为前置,这样是不正确的。正确的使用方法是每次使用 remove 方法之前都应该调用一次 .next() 方法。
解决方法
上述例子,换种写法:
it = newList.iterator();
while(it.hasNext()) {
FileNoUploadDto dto = it.next();
boolean removeFlag = flag;
for (int i = 0; i < fileUploadDtos.size(); i++) {
it.remove(); //第一次 remove
removeFlag = true;
break;
}
if (StringUtil.isEmptyList(resultDateList) || !resultDateList.contains(dto.getValDate()) && !removeFlag) {
it.remove(); //第二次 remove
}
}
其实就是加了一个是否可以执行第二次 remove 方法的标志。如果第一次 remove 方法没有执行,则 removeFlag 还是 false,前面有一次 .next() 方法的调用,可以执行第二次的 remove 方法;如果第一次的 remove 方法执行了,那么 removeFlag 就是 true,就不允许执行第二次 remove 方法了。避免了两次 remove 方法,但前面只有一次 .next() 方法情况的出现。
其实总结就一句话:当 Iterator 执行 remove 方法时,如果迭代器尚未调用 next 方法,或者在上一次调用 next 方法之后已经调用了 remove 方法,那么再次调用 remove 方法时就会抛出上述异常!具体情况具体分析,只要保证上述条件成立即可。
希望本文能够帮到你,如有错误,望指正!
我向你敬礼啊,Salute!