在多数情况下使用asList或subList都是只读的,因此一般不会出现问题,但当有需要对list 数据修改时就会抛出异常。
有时在对一个数据进行一些处理时,数组没有 List 一些快捷方法,此时就需要将数据转为 List 使用,因此使用不当而引发程序异常
import java.util.Arrays;
import java.util.List;
public class Test {
public static void main(String[] args) {
Integer[] numbers = new Integer[] {1, 2, 3, 4, 5};
List list = Arrays.asList(numbers);
System.out.println("包含 3:" + list.contains(3));
System.out.println("包含 6:" + list.contains(6));
}
}
结果输出:
当需要对 list 进行操作时会抛出异常
import java.util.Arrays;
import java.util.List;
public class Test {
public static void main(String[] args) {
Integer[] numbers = new Integer[] {1, 2, 3, 4, 5};
List list = Arrays.asList(numbers);
System.out.println("包含 3:" + list.contains(3));
System.out.println("包含 6:" + list.contains(6));
// 异常操作
list.add(7);
}
}
通过查看Arrays 源码发现,asList 里面返回的 ArrayList 是位于 Arrays 里面的一个私有类
这个类和java.util.ArrayList一样,也继承了AbstractList
在 Arrays.ArrayList里面,它重写了 set、get、indexOf、contains等方法但没有重写 add 方法,这导致无法对 list 进行元素增加
因此,对于 asList 返回的 list 我们可以用来修改、获取等操作,但是无法增加元素和删除元素,因为 asList 引用的内部类 ArrayList 没有重写 add 和 remove 这些方法
对于这个问题进行深度研究发现,list 和numbers其实是公用的一个对象,对 list 操作其实就是对numbers操作,例如:将 list 第一个元素改为 9,其对应的 numbers第一个元素也将会变为 9
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
public class Test {
public static void main(String[] args) {
Integer[] numbers = new Integer[] {1, 2, 3, 4, 5};
List list = Arrays.asList(numbers);
System.out.println("list包含 3:" + list.contains(3));
System.out.println("list包含 6:" + list.contains(6));
System.out.println("list包含 9:" + list.contains(9));
list.set(0,9);
System.out.println("list包含 9:" + list.contains(9));
System.out.println("numbers[0]:" + numbers[0]);
}
}
结果:
事故背景:原先有个业务需要对一批数据订阅,订阅数据是分段发送的,比如一次查询 1000 条,订阅的时候需要每次只发不超过 100 条,这个业务代码跑了很久一直没问题,直到一次功能迭代,新增了一个订阅,需要将这 1000 条数据和另外的几十条比较特殊的数据放在一起生成文件上传的 FTP,开发人员直接将需要加入的数据用 addAll 给加到原集合里面,然后再使用子集合时就发现程序抛出java.util.ConcurrentModificationException异常
import java.util.ArrayList;
import java.util.List;
public class Test {
public static void main(String[] args) {
List sourceList = new ArrayList() {{
add(1);
add(2);
add(3);
add(4);
add(5);
}};
List subList = sourceList.subList(0, 3);
System.out.println("sourceList: " + sourceList);
System.out.println("subList: " + subList);
sourceList.add(6);
System.out.println("subList: " + subList);
}
}
结果:这种情况也只是修改原集合结构后使用了子集合才会抛异常
import java.util.ArrayList;
import java.util.List;
public class Test {
public static void main(String[] args) {
List sourceList = new ArrayList() {{
add(1);
add(2);
add(3);
add(4);
add(5);
}};
List subList = sourceList.subList(0, 3);
System.out.println("sourceList: " + sourceList);
System.out.println("subList: " + subList);
subList.add(6);
System.out.println("sourceList: " + sourceList);
System.out.println("subList: " + subList);
}
}
结果:在子集合末尾追加的元素,在原集合中的位置取决于子集合的toIndex
import java.util.ArrayList;
import java.util.List;
public class Test {
public static void main(String[] args) {
List sourceList = new ArrayList() {{
add(1);
add(2);
add(3);
add(4);
add(5);
}};
List subList = sourceList.subList(0, 3);
System.out.println("sourceList: " + sourceList);
System.out.println("subList: " + subList);
sourceList.set(0,2);
System.out.println("sourceList: " + sourceList);
System.out.println("subList: " + subList);
subList.set(0,3);
System.out.println("sourceList: " + sourceList);
System.out.println("subList: " + subList);
}
}
结果:修改了原集合元素子集合也会修改,修改了子集合原集合也会修改