subList返回原List的实时视图而非副本,修改会双向同步;需显式new ArrayList(subList)获取独立副本;其参数为左闭右开区间,不支持addAll、clear等操作,遍历时严禁修改原列表或自身结构。

subList 返回的是原 List 的实时视图,不是副本
调用 subList 得到的不是新集合,而是对原 List 的一个“窗口”——所有修改都会穿透到原列表,原列表变动也会立刻反映在子视图里。这是最常被误以为是“复制”的地方。
- 对
subList调用add()、remove()、set(),等价于直接操作原列表对应位置 - 原列表用
add()或remove()改了长度,再访问subList可能抛ConcurrentModificationException(尤其在ArrayList中) - 想拿一份独立副本?得显式构造:
new ArrayList(list.subList(from, to))
下标越界会直接抛 IndexOutOfBoundsException
subList(fromIndex, toIndex) 的两个参数不是“起始索引 + 长度”,而是左闭右开区间:包含 fromIndex,不包含 toIndex。常见错误是把 toIndex 当成“末尾索引”或“元素个数”传。
-
fromIndex必须 ≥ 0,toIndex必须 ≤ 原列表size() -
fromIndex > toIndex会立即报错,哪怕两者都在合法范围内(比如list.subList(5, 3)) - 空列表调用
subList(0, 0)是合法的,返回空视图;但subList(0, 1)就会崩
subList 不支持 addAll、clear 等部分 List 操作
虽然 subList 返回类型是 List,但它只实现了部分接口方法。很多看似合理操作会在运行时失败。
-
subList.addAll(...)和subList.clear()在ArrayList中抛UnsupportedOperationException -
subList.retainAll(...)、subList.removeAll(...)同样不支持 - 安全可用的操作主要是:
get()、set()、size()、iterator()、listIterator(),以及有限制的add()/remove()(仅限在视图范围内插入/删除)
并发修改检查严格,遍历 subList 时别碰原列表
subList 共享原列表的 modCount。只要原列表结构变了(增删元素),哪怕只是调用了一次 add(),后续对 subList 的任何结构性操作或迭代都可能触发 ConcurrentModificationException。
- 遍历
subList时,不要在循环体里调用原列表的add()或remove() - 也不建议一边遍历
subList,一边调用它的add()或remove()(除非你清楚它如何影响内部指针) - 如果必须动态调整,先转成独立列表:
new ArrayList(subList),再操作
实际用的时候,最麻烦的不是怎么写这行代码,而是忘了它根本不是个“真列表”——它没自己的数据,没自己的生命周期,只有一根线连着原列表。稍不注意,改哪儿崩哪儿。










