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,如图所示:

image.png

  • 该对象是ArrayList的一个内部类,存储了原列表的一个偏移量,并且直接把原对象的modCount赋值给了内部类SubList的modCount,但针对原列表list的操作,该内部类是无感知的如下图所示:

image.png

  • 当遍历或操作内部类SubLIst时,会针对该类的modCount做一个check如图所示

image.png

  • 如果sublist的modCount和原modCount不一致,会抛ConcurrentModificationException异常;

image.png

解决办法

一行代码

List<String>subList=new ArrayList<>(list.subList(0,1));
复制代码

image.png

总结:

  • 截取操作后如果不需要原对象则可以进行该操作,但需求变更或者其他可能会导致后面有这么操作引起不必要的麻烦;

    扫描二维码关注公众号,回复: 14165250 查看本文章
  • 如果截取后有后续操作,建议创建一个新对象

猜你喜欢

转载自juejin.im/post/7100508447992446989