内存分页会用到sublist,业务里面比较常用的场景就是多线程跑批,需要先拆分任务。
文章目录
- 注意事项(demo)
- 应用(demo)
- 详细介绍
注意事项(demo)
- 结论:sublist获取的是原列表的镜像;改子列表不会报错、但会影响原列表;改原列表会导致子列表报错,子列表依赖原列表
public static void main(String[] args) {List<String> list = new ArrayList<>(Arrays.asList("A", "B", "C", "D"));List<String> subList = list.subList(1, 3); //[1, 3)log.info("=== 刚截取的");log.info("list = {}", list);log.info("subList = {}", subList);subList.add("E");log.info("=== 修改子列表后");log.info("list = {}", list);log.info("subList = {}", subList);list.add("K");log.info("=== 修改原列表后");log.info("list = {}", list);log.info("subList = {}", subList); //TODO subList = [FAILED toString()] 异常java.util.ConcurrentModificationExceptionList<String> subList2 = new ArrayList<>(list.subList(1, 3));subList2.add("F");log.info("=== 截取子列表重新创建新list之后");log.info("list = {}", list.size());log.info("subList = {}", subList); //TODO subList = [FAILED toString()] 异常java.util.ConcurrentModificationExceptionlog.info("subList2 = {}", subList2);log.info("结论:sublist获取的是原列表的镜像;改子列表不会报错、但会影响原列表;改原列表会导致子列表报错,子列表依赖原列表");}
执行结果:
应用(demo)
- 内存分页
public static void main(String[] args) {//三个测试样本List<String> list = new ArrayList<>(Arrays.asList("A", "B", "C", "D", "E", "F", "G", "H"));//List<String> list = new ArrayList<>(Arrays.asList("A", "B", "C", "D", "E", "F", "G", "H", "I"));//List<String> list = new ArrayList<>(Arrays.asList());int groupSize = 3; //一组3个int totalSize = list.size();int handleTimes = totalSize == 0 ? 0 : (totalSize%groupSize == 0 ? (totalSize/groupSize) : (totalSize/groupSize + 1));//处理次数for (int i = 1; i <= handleTimes; i++) {List<String> subList = null;if(i == handleTimes) {subList = list.subList((i-1)*groupSize, totalSize);} else {subList = list.subList((i-1)*groupSize, i*groupSize);}log.info("分组 - {}", subList);}}
执行结果:
详细介绍
在使用 subList 方法时,需要注意以下几个关键点,以避免潜在的问题:
- 子列表与原列表共享数据
subList 返回的子列表不是一个新的列表,而是原列表的视图(view)。
对子列表的修改会影响原列表,反之亦然。
List list = new ArrayList<>(Arrays.asList(“A”, “B”, “C”, “D”));
List subList = list.subList(1, 3);
subList.set(0, “X”); // 修改子列表
System.out.println(list); // 输出: [A, X, C, D]
- 子列表不能独立于原列表操作
如果修改了原列表的结构(如增删元素),子列表会变得不可用,操作时会抛出 ConcurrentModificationException。
List list = new ArrayList<>(Arrays.asList(“A”, “B”, “C”, “D”));
List subList = list.subList(1, 3);
list.add(“E”); // 修改原列表结构
subList.get(0); // 抛出 ConcurrentModificationException
解决办法:
如果需要独立的子列表,建议创建一个新的列表:
List independentList = new ArrayList<>(list.subList(1, 3));
- 索引范围必须合法
subList(fromIndex, toIndex) 方法要求:
fromIndex >= 0
toIndex <= list.size()
fromIndex <= toIndex
如果索引越界,会抛出 IndexOutOfBoundsException。
List list = new ArrayList<>(Arrays.asList(“A”, “B”, “C”, “D”));
List subList = list.subList(2, 5); // 抛出 IndexOutOfBoundsException
- 子列表的并发问题
如果在多线程环境中使用 subList,要注意线程安全问题。
推荐在外部同步访问原列表和子列表,或使用线程安全的集合(如 Collections.synchronizedList)。 - 子列表的序列化问题
由于子列表依赖于原列表,因此在序列化时需要确保原列表也可序列化。否则,序列化子列表会失败。 - 使用场景
推荐:
用于对列表的一个范围执行只读操作。
用于分块操作(如分页处理)。
避免:
长期保存子列表引用,容易导致意外问题。
通过了解这些注意事项,可以更安全和高效地使用 subList 方法。