项目中使用Java中List.subList()的注意事项

使用介绍

在Java中,subListList接口的一个方法,用于获取原始列表的子列表

方法的声明如下

List<E> subList(int fromIndex, int toIndex);
  • fromIndex:起始索引(包括)
  • toIndex:结束索引(不包括)
List<Object> list = new Arraylist<>();List<Object> subList = list.subList(0, 5);

返回的子列表是原始列表的一个视图,对子列表的修改会反映在原始列表上,反之亦然。

例如,下面的语句从列表中移除了元素的范围:

list.subList(from, to).clear();

下面是一个简单的例子:

List<String> originalList = new ArrayList<>(Arrays.asList("A", "B", "C", "D", "E"));
List<String> subList = originalList.subList(1, 4);
System.out.println("subList = " + subList); // 子列表包括索引 1,2,3  输出:[B, C, D]
System.out.println("originalList = " + originalList); // 输出:[A, B, C, D, E]subList.add("F");
System.out.println("subList = " + subList); // 输出: [B, C, D, F]
System.out.println("originalList = " + originalList);// 输出:[A, B, C, D, F, E] 因为通过subList视图对索引为4的位置添加了一个ForiginalList.add("G");
// 调用subList()后,如果再对原list进行操作同时对subList()也进行操作(打印、添加、清除),都会报错ConcurrentModificationException,因为这会修改视图的结构
// subList.add("H") java.util.ConcurrentModificationException
// System.out.println(subList);  java.util.ConcurrentModificationExceptionSystem.out.println("originalList = " + originalList); // 输出:[A, B, C, D, F, E, G]
originalList.subList(1, 2).clear();
System.out.println("originalList = " + originalList); // 输出: [A, C, D, F, E, G] 因为通过视图对索引为1的数据进行了清除

注意事项

  • ArrayList的subList结果不可强转成ArrayList,否则会抛出ClassCastException 异常,即java.util.RandomAccessSubList cannot be cast to java.util.ArrayList.

说明:subList 返回的是 ArrayList 的内部类 SubList,并不是 ArrayList ,而是 ArrayList 的一个视图,对于 SubList 子列表的所有操作最终会反映到原列表上。

  • 在 subList 场景中,高度注意对原集合元素个数的修改,会导致子列表的遍历、增加、 删除均会产生 ConcurrentModificationException 异常。
  • 索引范围: fromIndextoIndex 是左闭右开的范围,即包括 fromIndex 处的元素,但不包括 toIndex 处的元素。
  • 修改原列表: 对子列表的修改会反映在原列表上,反之亦然。这是因为子列表实际上是原列表的一个视图。
  • 不支持结构性修改: 在子列表的视图上不支持对原列表的结构性修改(例如插入、删除元素),否则会抛出ConcurrentModificationException异常。结构性修改是指改变原列表的大小或者使其元素的数量发生变化的操作。
  • 子列表可以增、删、改,但是原列表不支持,理由同上
  • subList()返回的不是List!是Sublist,不是原来的类型
 public List<E> subList(int fromIndex, int toIndex) {return (this instanceof RandomAccess ?new RandomAccessSubList<>(this, fromIndex, toIndex) :new SubList<>(this, fromIndex, toIndex));}声明:class SubList<E> extends AbstractList<E>{}
  •  LinkedList并没有覆盖这个方法.ArryList自己覆盖了这个方法,返回的是java.util.ArrayList.SubList

public List<E> subList(int fromIndex, int toIndex) {subListRangeCheck(fromIndex, toIndex, size);return new SubList(this, 0, fromIndex, toIndex);
}
声明:
private class SubList extends AbstractList<E> implements RandomAccess {}

wAAACH5BAEKAAAALAAAAAABAAEAAAICRAEAOw==

看来ArryList处处体现出RandomAccess接口的特性——支持随机访问。

  • java.util.AbstractList.clear()方法就是subList的clear方法
public void clear() {removeRange(0, size());
}...
// ArrayList的覆盖
public void clear() {modCount++;// clear to let GC do its workfor (int i = 0; i < size; i++)elementData[i] = null;size = 0;
}...
// LinkedList的覆盖
public void clear() {for (Node<E> x = first; x != null; ) {Node<E> next = x.next;x.item = null;x.next = null;x.prev = null;x = next;}first = last = null;size = 0;modCount++;
}...
// 根据上面,截短一个List的正确姿势
list.subList(from, to).clear();

项目实战

大家可以看一下我的慢查询优化实战文章

在最开始分页慢查询优化没有得到较好的解决方案时,我的操作是直接获取到全部数据的List,然后对List进行截取,达到分页的效果,这是相关的代码

public static <T> IPage<T> listToPage(List<T> list, Integer current, Integer size){IPage<T> iPage = new Page<>(current,size);iPage.setTotal(list.size());int startIndex = (int)((current - 1)*size);if(null == list || list.isEmpty() || startIndex > list.size()){iPage.setRecords(new ArrayList<>());}else {int toIndex = (int)(current*size);iPage.setRecords(list.subList(startIndex,toIndex > list.size() ? list.size() : toIndex));}return iPage;}

大家可以看到,我对List是只截取不操作的,也就不会出现bug

注意!subList是返回一个镜像而不是新示例,用了得保证原来的list不能更改!

over

参考

Java中List的subList()方法及使用注意事项_list sublist-CSDN博客

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/310348.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

【数据结构】八、查找

一、基本概念 静态查找&#xff1a;只查找&#xff0c;不改变集合内数据元素 动态查找&#xff1a;有则输出元素&#xff0c;无则添加元素 二、静态查找表 2.1顺序查找 在线性表、链表、树中依次查找 2.2折半查找&#xff08;二分查找&#xff09; 在有序的线性表中&…

模式识别与机器学习-集成学习

集成学习 集成学习思想过拟合与欠拟合判断方法 K折交叉验证BootstrapBagging随机森林的特点和工作原理&#xff1a; BoostingAdaBoost工作原理&#xff1a;AdaBoost的特点和优点&#xff1a;AdaBoost的缺点&#xff1a; Gradient Boosting工作原理&#xff1a;Gradient Boostin…

【已解决】 ubuntu apt-get update连不上dl.google.com

在终端使用apt-get update时&#xff0c;连接dl.google.com超时&#xff0c;一直卡在0%&#xff0c;原因是当前ip无法ping到google&#xff08;墙&#xff09;。 解决方法&#xff1a; dl.google.com国内可用IP 选一个&#xff0c;然后按以下命令操作&#xff1a; cd ~ vim …

通信原理课设(gec6818) 007:语音识别

目录 1、去科大讯飞官网下载对应的sdk 2、科大讯飞文件夹的意思 3、配置ARM的录音环境 4、编程实现语音识别 我们的需求是将一个语音文件从客户端传到服务器&#xff0c;因此我们最好是选用tcp 现在市面上面常用的语音识别解决方案为&#xff1a;科大讯飞c和百度c 离…

【BERT】深入BERT模型2——模型中的重点内容,两个任务

前言 BERT出自论文&#xff1a;《BERT&#xff1a;Pre-training of Deep Bidirectional Transformers for Language Understanding》 2019年 近年来&#xff0c;在自然语言处理领域&#xff0c;BERT模型受到了极为广泛的关注&#xff0c;很多模型中都用到了BERT-base或者是BE…

数据库中的锁

锁 锁冲突是针对事务的&#xff0c;另一个事务能不能申请上锁&#xff0c;是和其他事务竞争。 一个事务内部可以加很多锁&#xff0c;互相并不会冲突。 级联回滚调度 多个事务有依赖关系&#xff0c;如果一个事务回滚&#xff0c;那么所有事务也需要回滚。 冲突的数据加锁安…

计算机毕业设计------SSM游戏点评网站

项目介绍 本项目分为前后台&#xff0c;前台为普通用户登录&#xff0c;后台为管理员登录&#xff1b; 管理员角色包含以下功能&#xff1a; 管理员登录,管理员管理,网站用户管理,游戏资讯管理,游戏类型管理,城市信息管理,竞技场管理,游戏信息管理,游戏评价信息管理等功能。…

集合基础知识点

集合基础 1. 集合的由来 当 Java 程序中需要存放数据的时候&#xff0c;通常会定义变量来实现数据的存储&#xff0c;但是&#xff0c;当需要存储大量数据的时候该怎么办呢&#xff1f;这时首先想到的是数组&#xff0c;但是&#xff01;数组只能存放同一类型的数据&#xff…

CLion中使用C/C++ Single File Execution插件编译和运行单个文件

在开发C/C程序时&#xff0c;尽管项目通常以组织良好的结构进行管理&#xff0c;但有时我们可能只需要快速测试或运行单个C或C源文件。对于这种情况&#xff0c;JetBrains CLion IDE提供了一个便捷的解决方案——通过安装名为“C/C Single File Execution”的插件来实现对单个源…

机器学习——主成分分析(PCA)

目录 一、特征维度约减 1. 为何要维度约减 2. 特征维度约减的概念 二、主成分分析 1. 主成分 2. 主成分的代数定义 3. 主成分的代数推导 3.1. 第一主成分 3.2. 第二主成分 4. 主成分分析算法流程 三、主成分分析算法实现 四、总结 一、特征维度约减 1. 为何要维度…

深度学习-数据基本使用

数据使用 文章目录 数据使用一、数据的获取1、图片爬虫工具2、视频爬虫工具3、复杂的爬虫工具(flickr)4、按照用户的ID来爬取图片5、对一些特定的网站进行爬&#xff08;摄影网站&#xff09;(图虫、500px&#xff0c;花瓣网等等)6、爬虫合集 二、数据整理1、数据检查与归一化2…

VS Code中文改成空格,把空行去掉

在VS Code中同时按下CtrlH使用(.*[\u4E00-\u9FA5])|([\u4E00-\u9FA5].*)正则文法匹配中文&#xff0c;然后按照下图操作可以把中文改成空格。 完成之后如下图&#xff1a; ^\s*(?\r?$)\n可以匹配空行&#xff0c;然后按下图操作可以把空行去掉。