之前说每周坚持更新一篇博客,不管什么类型的都好,但自己还是没能做到,不过从这周开始我会坚持每周至少更新一篇博客!说到做到!
相信大家在编写java代码时,一个稍不留神就会触发到ConcurrentModificationException,直译过来也就是并发修改异常,那么什么样的情况会导致这种异常抛出呢?我在这周上班时就遇到过了,首先先来一段我写的代码,如下所示:
public static List<String> filterData(List<String> originList, List<String> targetList){
if (CollUtil.isNotEmpty(originList) && CollUtil.isNotEmpty(targetList)){
originList.forEach(origin ->{
targetList.forEach(target ->{
if (target.equals(origin)){
originList.remove(origin);
}
});
}
return originList;
}
大家可以看出上面的代码还是有一定的问题的,经过分析,可以看到我在遍历originList的同时又去对originList的内容进行remove,这样会容易触发到集合类中的 fail-fast(快速失败)机制,直接抛出了ConcurrentModificationException这个异常,网上有一段资料对这个异常描述得还是挺到位的,我贴出来给大家看下:
Essentially, the ConcurrentModificationException is used to fail-fast when something we are iterating on is modified.
从字面意思上就可以很容易明白,如果在遍历迭代比如集合中的数据的同时,你又去篡改集合里面的数据,这就会触发ConcurrentModificationException这个异常,以此来响应这个集合类中的快速失败机制。
原因我们已经明白了,那么我们如何解决呢?网上有些资料说可以使用一些线程安全的集合类,比如CopyOnWriteArrayList等等来替代ArrayList,但我使用了一个更好的方法,话不多说,我先贴出我修改后的代码:
public static List<String> filterData(List<String> originList, List<String> targetList){
if (CollUtil.isNotEmpty(originList) && CollUtil.isNotEmpty(targetList)){
targetList.forEach(target ->{
originList.removeIf(origin -> origin.equals(target));
});
}
return originList;
}
大家通过比较可以看出,我直接不同这么麻烦在外围遍历originList,而是以functional programming(函数式编程)的方式来轻松解决这个问题。分析removeIf里面的源码,我发现里面就是使用Iterator的方式来实现的,这样确保了在遍历originList的同时删除特定元素的安全性,大家有兴趣的话可以分析下里面的源码。
那么除了上述我说的方法之外,还有其它方法吗?当然有!这里我贴出一个网址,这个网址里面就针对ConcurrentModificationException列出了不同的剖解决方案,还是不错的!
Avoiding the ConcurrentModificationException in Java
还有一个csdn博客对于这个异常产生原因的分析得比我还更深入,大家不妨也看一下。
ConcurrentModificationException产生原因及解决方法
好的,今天就讲这么多,希望我能帮助到大家,谢谢!如果我有说得不对的地方,希望大家踊跃提出来!