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

news2025/4/24 14:24:41

使用介绍

在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的位置添加了一个F


originalList.add("G");
// 调用subList()后,如果再对原list进行操作同时对subList()也进行操作(打印、添加、清除),都会报错ConcurrentModificationException,因为这会修改视图的结构
// subList.add("H") java.util.ConcurrentModificationException
// System.out.println(subList);  java.util.ConcurrentModificationException

System.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 work
    for (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.coloradmin.cn/o/1345584.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

DrGraph原理示教 - OpenCV 4 功能 - 颜色空间

前言 前段时间&#xff0c;甲方提出明确需求&#xff0c;让把软件国产化。稍微研究了一下&#xff0c;那就转QT开发&#xff0c;顺便把以前的功能代码重写一遍。 至于在Ubuntu下折腾QT、OpenCV安装事宜&#xff0c;网上文章很多&#xff0c;照猫画虎即可。 这个过程&#xff0…

【JVM】一篇通关JMM内存模型

JMM内存模型 1. 原子性1-1. 问题分析1-2. 问题解决 2. 可见性2-1. 问题分析2-2. 问题解决 3. 有序性3-1. 问题分析3-2. 问题解决 4. CAS与原子性5. synchronized 优化 1. 原子性 很多人将【java 内存结构】与【java 内存模型】傻傻分不清&#xff0c;【java 内存模型】是 Java…

zookeeper之集群搭建

1. 集群角色 zookeeper集群下&#xff0c;有3种角色&#xff0c;分别是领导者(Leader)、跟随着(Follower)、观察者(Observer)。接下来我们分别看一下这三种角色的作用。 领导者(Leader)&#xff1a; 事务请求&#xff08;写操作&#xff09;的唯一调度者和处理者&#xff0c;保…

ARCGIS PRO SDK 访问Geometry对象

一、Geometry常用对象 二、主要类 1、ReadOnlyPartCollection&#xff1a;Polyline 和 Polygon 使用的 ReadOnlySegmentCollection 部件的只读集合&#xff0c;属性成员&#xff1a;​ 名字描述Count获取 ICollection 中包含的元素数。TIEM获取位于指定索引处的元素。Spatial…

STM32——F407定时器概述

1 定时器分类 定时器类型数量位号位宽时钟捕获/比较输出DMA请求计数互补输出基本2TIM6,TIM716bitAPB1-有递增-通用2TIM2,TIM532bitAPB14通道有递增、递减、中心对齐-通用2TIM3,TIM432bitAPB14通道有递增、递减、中心对齐-通用1TIM916bitAPB14通道有递增-通用2TIM10、TIM1116bi…

CorelDRAW2024新功能有哪些?CorelDRAW2024最新版本更新怎么样?

CorelDRAW2024新功能有哪些&#xff1f;CorelDRAW2024最新版本更新怎么样&#xff1f;让我们带您详细了解&#xff01; CorelDRAW Graphics Suite 是矢量制图行业的标杆软件&#xff0c;2024年全新版本为您带来多项新功能和优化改进。本次更新强调易用性&#xff0c;包括更强大…

Cisco模拟器-企业网络部署

某企业园区网有&#xff1a;2个分厂&#xff08;分别是&#xff1a;零件分厂、总装分厂&#xff09;1个总厂网络中心 1个总厂会议室&#xff1b; &#xff08;1&#xff09;每个分厂有自己的路由器&#xff0c;均各有&#xff1a;1个楼宇分厂网络中心 每个楼宇均包含&#x…

{MySQL}索引事务和JDBC

提示&#xff1a;文章写完后&#xff0c;目录可以自动生成&#xff0c;如何生成可参考右边的帮助文档 文章目录 前言一、索引1.1索引是什么1.2作用1.3代码 二、事务2.1什么是事务2.2使用 三.JDBC总结 前言 接着上次&#xff0c;继续讲下MySQL 提示&#xff1a;以下是本篇文章正…

QT中的信号与槽的讲解

文章目录 信号及其特点槽及其特点代码演示标准信号与标准槽函数方式一方式二 自定义信号和槽connect()函数信号和槽函数存在函数重载的情况下Qt的信号槽机制注意事项 信号及其特点 信号&#xff1a;是一种特殊的函数&#xff0c;又称信号函数&#xff0c;俗称信号&#xff0c;…

FreeRTOS学习--41讲 信号量

信号量的定义 是一种解决同步问题的机制&#xff0c;实现对共享资源的有序访问 信号量特点&#xff1a; 当计数值大于0&#xff0c;代表有信号量资源&#xff1b;释放信号量&#xff0c;信号量计数值1;获取则-1 队列和信号量的差异 二值信号量&#xff1a; a.相当于队列长度等…

用idea跑起十多年前的项目

一、eclipse的项目 先删掉一些eclipse的配置文件 二、在idea中导入项目 1、导入成功后&#xff0c;先【锤一下】 2、然后发现编译不通过&#xff0c;非常多的报错信息&#xff0c;逐一解决报错 &#xff08;1&#xff09;tomcat7配置报错 &#xff08;2&#xff09;先删除tom…

将本地工作空间robot_ws上传到gitee仓库

git config --global user.name "geniusChinaHN" git config --global user.email "12705243geniuschinahnuser.noreply.gitee.com" cd ~/robot_ws #git init#创建原始仓库时候用 git add . git commit -m "上传文件内容描述" #git remote add r…

【教程】Typecho Joe主题开启并修复壁纸相册不显示问题

转载请注明出处&#xff1a;小锋学长生活大爆炸[xfxuezhang.cn] 背景说明 Joe主题本身支持“壁纸”功能&#xff0c;其实就是相册。当时还在网上找了好久相册部署的开源项目&#xff0c;太傻了。 但是网上教程很少&#xff0c;一没说如何开启壁纸功能&#xff0c;二没说开启后为…

Java Log 学习笔记

参考文章&#xff1a; 1.Java 日志从入门到实战 2.Java日志框架的发展历史&#xff0c;你不想了解一下吗 背景 想自定义 logback 配置文件进行日志分级别记录到不同文件&#xff0c;遇到了几个问题&#xff08;使用的是 spring-boot 构建的项目&#xff0c;spring-boot 版本为…

开源可观测性平台Signoz(四)【链路监控及数据库中间件监控篇】

转载说明&#xff1a;如果您喜欢这篇文章并打算转载它&#xff0c;请私信作者取得授权。感谢您喜爱本文&#xff0c;请文明转载&#xff0c;谢谢。 前文链接&#xff1a; ​​开源可观测性平台Signoz系列&#xff08;一&#xff09;【开篇】​​ ​​开源可观测性平台Signoz&…

记录一下imx6ull linux 5.10.9多点电容触摸屏驱动报错问题解决方法

最近再研究如何将linux 5.10.9移植到imx6ull&#xff0c;用的原子的开发板&#xff0c;在移植电容触摸屏驱动时报错gpio gpiochip0: (209c000.gpio): gpiochip_lock_as_irq: tried to flag a GPIO set as output for IRQ&#xff0c;如下图&#xff1a; 该错误的意思就是尝试将…

MongoDB Certified Associate Developer 认证考试心得

介绍 前段时间通过了 MongoDB Associate Developer 考试&#xff0c;也记下了一些心得&#xff0c;结果忘记发出来了&#xff0c;现在重新整理下。通过考试后证书是这样的: MongoDB 目前有两个认证证书 1. MongoDB Associate Developer 认证掌握使用MongoDB 来构建现代应用…

前端八股文(工程化篇)

目录 1.常用的git命令有哪些&#xff1f; 2.git rebase和git merge的区别 3.有哪些常见的Loader和Plugin&#xff1f; 4.webpack的构建流程 5.bundle,chunk,module是什么&#xff1f; 6.如何提高webpack的打包速度 7.vite比webpack快在哪里 8.说一下你对Monorepo的理解 …

EOS开发Ubuntu安装EOSIO.CDT(Install the EOSIO.CDT)

EOS开发Ubuntu安装EOSIO.CDT&#xff08;Install the EOSIO.CDT&#xff09; EOSIO.CDT介绍&#xff1a;EOSIO合约开发工具包&#xff0c;简称CDT&#xff0c;是与合约编译相关的工具集合。而且后续教程主要使用 CDT 来编译合约和生成 ABI&#xff0c;不要忽略。 刚才我们安装好…

欢迎来到Web3.0的世界:Solidity智能合约安全漏洞分析

智能合约概述 智能合约是运行在区块链网络中的一段程序&#xff0c;经由多方机构自动执行预先设定的逻辑&#xff0c;程序执行后&#xff0c;网络上的最终状态将不可改变。智能合约本质上是传统合约的数字版本&#xff0c;由去中心化的计算机网络执行&#xff0c;而不是由政府…