ArrayList的subList返回原列表的实时双向同步视图,共享底层数组,支持add/remove/set等操作但受索引边界约束;原列表结构性修改会导致子列表后续操作抛ConcurrentModificationException。

ArrayList 的 subList 返回的是原列表的视图,不是独立副本,修改它会直接影响原列表,反之亦然。
subList 是只读视图?不,它是可修改的(但有约束)
subList 返回的是原 ArrayList 的一个实时、双向同步的视图,底层共享同一数组。它支持 add、remove、set 等操作,但所有操作都受限于原始列表的状态和索引边界。
- 调用
list.subList(1, 4)后,对子列表的set(0, "x")等价于对原列表索引 1 处赋值 - 在子列表末尾
add("y"),等价于在原列表对应位置插入,原列表长度随之增加 - 若原列表在子列表创建后被结构性修改(如 add/remove 元素),再访问子列表会抛
ConcurrentModificationException
常见陷阱:结构修改导致失效
subList 内部维护了对原列表 modCount 的快照。一旦原列表发生任何结构性变更(add、remove、clear),子列表的后续操作(包括 size()、get()、iterator())都会触发异常。
- 错误示例:
List<String> list = new ArrayList<>(Arrays.asList("a","b","c","d"));<br> List<String> sub = list.subList(1, 3); // ["b", "c"]<br> list.add("e"); // 原列表结构改变<br> sub.get(0); // 抛 ConcurrentModificationException - 安全做法:避免在获取 subList 后继续修改原列表;如需独立操作,应显式复制:
new ArrayList(subList)
边界索引必须合法,且不可越界
subList 的 fromIndex 和 toIndex 遵循“左闭右开”规则(包含 fromIndex,不包含 toIndex),且必须满足:0 ≤ fromIndex ≤ toIndex ≤ list.size()。越界立即抛 IndexOutOfBoundsException。
立即学习“Java免费学习笔记(深入)”;
-
list.subList(0, list.size())是合法的,返回完整视图 -
list.subList(2, 2)返回空列表(有效),但仍是原列表的视图 -
list.subList(-1, 3)或list.subList(2, 10)直接报错
实际建议:何时用、怎么用更稳妥
subList 适合临时切片读写,不适合长期持有或跨线程共享。
- 批量处理某段数据时,优先用 subList + for-each 或 Stream.subList(...)(Java 16+)
- 需要持久化或隔离修改,请转成新 ArrayList:
new ArrayList(list.subList(i, j)) - 不要将 subList 作为方法返回值暴露给调用方,除非明确约定其生命周期和并发约束
- 调试时注意:打印 subList 可能触发 toString(),而 toString() 内部调用 size() —— 若此时原列表已被改,仍会异常
不复杂但容易忽略:它不是工具方法,而是一个带状态的活视图。


















