这个结论对于我们日常的开发工作, 倒是起不到太大的帮助作用. 因为这些结论总结出的都是消极的结果, 而不是积极的结果. 不过, 这个结论倒是告诉我们:
如果你对一个
List
进行过subList()
的操作之后,
1. 千万不要再对原List
进行任何改动的操作(例如: 增删改), 查询和遍历倒是可以. 因为如果对原List
进行了改动, 那么后续只要是涉及到子List
的操作就一定会出问题. 而至于会出现什么问题呢? 具体来说就是:
(1) 如果是对原List
进行修改 (即: 调用set()
方法) 而不是增删, 那么子List
的元素也可能会被修改 (这种情况下不会抛出并发修改异常).
(2) 如果是对原List
进行增删, 那么此后只要操作了子List
, 就一定会抛出并发修改异常.
2. 千万不要直接对子List
进行任何改动的操作(例如: 增删改), 但是查询和间接改动倒是可以. 不要对子List
进行直接改动, 是因为如果在对子List
进行直接改动之前, 原List
已经被改动过, 那么此后在对子List
进行直接改动的时候就会抛出并发修改异常.
既然获取子 List
后会有这么多限制条件, 一不小心就会出错, 那我们还怎么操作这个子 List
呢? 或者说, 怎样才能安全地操作子 List
呢? 其实, 你可能已经注意到了我在上述结论中提到的间接二字. 是的, 我们可以通过间接的方式来安全地操作子 List
. 怎么间接呢? 其实, “间接” 和 “直接” 是相对的, 因为根据前边的分析, 子 List
会共用原 List
中后一部分的元素, 他们共同指向相同的对象, 这种共用对象的特性就是导致产生各种不安全结果的罪魁祸首. 如果我们将二者分别指向不同的对象, 岂不是就能避免不安全结果的产生? 也就是说, 我们需要让子 List
指向新的对象, 并且让新对象每个位置上的数值要和原 List
中相关位置上的数值相等即可. 于是就想到了以下两种间接的处理方式:
- 创建一个新的对象作为我们最终要操作的对象, 在其构造方法中, 将通过
subList()
方法获取到的子List
作为该构造方法的参数传入. 这时, 这个新对象内所包含的元素和子List
的完全相同, 但却指向的是不同的对象. 我们只需使用这个新创建的对象即可.
对于ArrayList
:
List<Integer> subList = new ArrayList<>(list.subList(2, list.size()));
对于 LinkedList
:
List<Integer> subList = new LinkedList<>(list.subList(2, list.size()));
- 创建一个新的对象作为我们最终要操作的对象, 然后调用这个新对象的
addAll()
方法, 将通过subList()
方法获取到的子List
作为addAll()
方法的参数传入, 这时, 这个新对象内所包含的元素和子List
的完全相同, 但却指向的是不同的对象. 我们只需使用这个新创建的对象即可.
对于ArrayList
:
List<Integer> subList = new ArrayList<>();
subList.addAll(list.subList(2, list.size()));
对于 LinkedList
:
List<Integer> subList = new LinkedList<>();
subList.addAll(list.subList(2, list.size()));