List.sublist操作报错-踩坑经验总结- 事故总结集锦 14(一周一更)
背景
我们在日常开发中经常会使用List对数据进行排序、查找、截取等操作。接下来我们看下因为List截取导致的踩坑现场。
【问题描述】
- 在正常的业务需求迭代过程中,我们需要对List里的数据进行截取,并生成新的subList,然后对原有的list进行add/remove操作,结果导致我们的subList循环、add/remove等操作报错。
【故障现象】
抛出异常: Exception in thread "main" java.util.ConcurrentModificationException
问题复现:
首先我们先用一段代码复现问题根源,如下所示:
- new一个list
- 增加三个测试数据
- new一个sublist,并且list.sublist(0,1)存储新的数据
- 原list新增一个测试数据no4
- 循环sublist报错
public static void main(String[] args) {
List<String> list = new ArrayList<>();
list.add("no1");
list.add("no2");
list.add("no3");
List<String>subList=list.subList(0,1);
list.add("no4");
System.out.println(subList);
for(String str:subList){
System.out.println(str);
}
}
结果如下:
Exception in thread "main" java.util.ConcurrentModificationException
at java.util.ArrayList$SubList.checkForComodification(ArrayList.java:1231)
at java.util.ArrayList$SubList.listIterator(ArrayList.java:1091)
at java.util.AbstractList.listIterator(AbstractList.java:299)
at java.util.ArrayList$SubList.iterator(ArrayList.java:1087)
at java.util.AbstractCollection.toString(AbstractCollection.java:454)
at java.lang.String.valueOf(String.java:2994)
at java.io.PrintStream.println(PrintStream.java:821)
at com.jd.cyclePredict.Test.main(Test.java:22)
原因分析:
- subList操作后会返回基于原数据对象的一个偏移量数据,创建一个新的对象SubList,如图所示:
- 该对象是ArrayList的一个内部类,存储了原列表的一个偏移量,并且直接把原对象的modCount赋值给了内部类SubList的modCount,但针对原列表list的操作,该内部类是无感知的如下图所示:
- 当遍历或操作内部类SubLIst时,会针对该类的modCount做一个check如图所示
- 如果sublist的modCount和原modCount不一致,会抛ConcurrentModificationException异常;
解决办法
一行代码:
List<String>subList=new ArrayList<>(list.subList(0,1));
总结:
-
截取操作后如果不需要原对象则可以进行该操作,但需求变更或者其他可能会导致后面有这么操作引起不必要的麻烦;
-
如果截取后有后续操作,建议创建一个新对象
转载自:https://juejin.cn/post/7100508447992446989