使用ArrayList中的subList方法

article/2025/10/21 20:07:15

集合是Java开发日常开发中经常会使用到的。在之前的一些文章中,我们介绍过一些关于使用集合类应该注意的事项,如《为什么阿里巴巴禁止在 foreach 循环里进行元素的 remove/add 操作》、《为什么阿里巴巴建议集合初始化时,指定集合容量大小》等。

关于集合类,《阿里巴巴Java开发手册》中其实还有另外一个规定:

本文就来分析一下为什么会有如此建议?其背后的原理是什么?

subList

subList是List接口中定义的一个方法,该方法主要用于返回一个集合中的一段、可以理解为截取一个集合中的部分元素,他的返回值也是一个List。

如以下代码:

以上代码输出结果为:

 
  1. [Hollis]

如果我们改动下代码,将subList的返回值强转成ArrayList试一下:

以上代码将抛出异常:

 
  1. java.lang.ClassCastException: java.util.ArrayList$SubList cannot be cast to java.util.ArrayList

不只是强转成ArrayList会报错,强转成LinkedList、Vector等List的实现类同样也都会报错。

那么,为什么会发生这样的报错呢?我们接下来深入分析一下。

底层原理

首先,我们看下subList方法给我们返回的List到底是个什么东西,这一点在JDK源码中注释是这样说的:

Returns a view of the portion of this list between the specifiedfromIndex, inclusive, and toIndex, exclusive.

也就是说subList 返回是一个视图,那么什么叫做视图呢?

我们看下subList的源码:

 
  1. public List<E> subList(int fromIndex, int toIndex) {
    subListRangeCheck(fromIndex, toIndex, size);
    return new SubList(this, 0, fromIndex, toIndex);
    }

这个方法返回了一个SubList,这个类是ArrayList中的一个内部类。

SubList这个类中单独定义了set、get、size、add、remove等方法。

当我们调用subList方法的时候,会通过调用SubList的构造函数创建一个SubList,那么看下这个构造函数做了哪些事情:

 
  1. SubList(AbstractList<E> parent,
    int offset, int fromIndex, int toIndex) {
    this.parent = parent;
    this.parentOffset = fromIndex;
    this.offset = offset + fromIndex;
    this.size = toIndex - fromIndex;
    this.modCount = ArrayList.this.modCount;
    }

可以看到,这个构造函数中把原来的List以及该List中的部分属性直接赋值给自己的一些属性了。

也就是说,SubList并没有重新创建一个List,而是直接引用了原有的List(返回了父类的视图),只是指定了一下他要使用的元素的范围而已(从fromIndex(包含),到toIndex(不包含))。

所以,为什么不能讲subList方法得到的集合直接转换成ArrayList呢?因为SubList只是ArrayList的内部类,他们之间并没有继承关系,故无法直接进行强制类型转换。

视图有什么问题

前面通过查看源码,我们知道,subList()方法并没有重新创建一个ArrayList,而是返回了一个ArrayList的内部类——SubList。

这个SubList是ArrayList的一个视图。

那么,这个视图又会带来什么问题呢?我们需要简单写几段代码看一下。

1、非结构性改变SubList

得到结果:

 
  1. sourceList : [H, O, L, L, I, S]
    sourceList.subList(2, 5) 得到List :
    subList : [L, L, I]
    subList.set(3,666) 得到List :
    subList : [L, 666, I]
    sourceList : [H, O, L, 666, I, S]

当我们尝试通过set方法,改变subList中某个元素的值得时候,我们发现,原来的那个List中对应元素的值也发生了改变。

同理,如果我们使用同样的方法,对sourceList中的某个元素进行修改,那么subList中对应的值也会发生改变。读者可以自行尝试一下。

2、结构性改变SubList

得到结果:

 
  1. sourceList : [H, O, L, L, I, S]
    sourceList.subList(2, 5) 得到List :
    subList : [L, L, I]
    subList.add(666) 得到List :
    subList : [L, L, I, 666]
    sourceList : [H, O, L, L, I, 666, S]

我们尝试对subList的结构进行改变,即向其追加元素,那么得到的结果是sourceList的结构也同样发生了改变。

3、结构性改变原List

得到结果:

 
  1. Exception in thread "main" java.util.ConcurrentModificationException
    at java.util.ArrayList$SubList.checkForComodification(ArrayList.java:1239)
    at java.util.ArrayList$SubList.listIterator(ArrayList.java:1099)
    at java.util.AbstractList.listIterator(AbstractList.java:299)
    at java.util.ArrayList$SubList.iterator(ArrayList.java:1095)
    at java.util.AbstractCollection.toString(AbstractCollection.java:454)
    at java.lang.String.valueOf(String.java:2994)
    at java.lang.StringBuilder.append(StringBuilder.java:131)
    at com.hollis.SubListTest.main(SubListTest.java:28)

我们尝试对sourceList的结构进行改变,即向其追加元素,结果发现抛出了ConcurrentModificationException。关于这个异常,我们在《一不小心就踩坑的fail-fast是个什么鬼?》中分析过,这里原理相同,就不再赘述了。

小结

我们简单总结一下,List的subList方法并没有创建一个新的List,而是使用了原List的视图,这个视图使用内部类SubList表示。

所以,我们不能把subList方法返回的List强制转换成ArrayList等类,因为他们之间没有继承关系。

另外,视图和原List的修改还需要注意几点,尤其是他们之间的相互影响:

  • 1、对父(sourceList)子(subList)List做的非结构性修改(non-structural changes),都会影响到彼此。
  • 2、对子List做结构性修改,操作同样会反映到父List上。
  • 3、对父List做结构性修改,会抛出异常ConcurrentModificationException。

所以,阿里巴巴Java开发手册中有另外一条规定:

5

如何创建新的List

如果需要对subList作出修改,又不想动原list。那么可以创建subList的一个拷贝:

 
  1. subList = Lists.newArrayList(subList);
    list.stream().skip(strart).limit(end).collect(Collectors.toList());

http://chatgpt.dhexx.cn/article/20gntCna.shtml

相关文章

sublist详解

接口中定义 List<E> subList(int fromIndex, int toIndex);1&#xff0c;该方法返回的是父list的一个视图&#xff0c;从fromIndex&#xff08;包含&#xff09;&#xff0c;到toIndex&#xff08;不包含&#xff09;。fromIndextoIndex 表示子list为空 2&#xff0c;父…

数据建模应用

数据建模应用 一、为什么要数据建模二、数据建模种类1、关系建模&#xff08;3NF&#xff09;2、维度建模 三、3NF数据建模1、范式介绍2、3NF建模实战 四、维度建模1、维度和指标的概念2、星型模型3、雪花模型4、星型与雪花模型对比5、维度建模测试案例 五、3NF建模与维度建模的…

分享大数据建模工具-大数据挖掘建模平台

大数据挖掘建模平台 是面向企业级用户的大数据挖掘建模平台。平台采用可视化操作方式&#xff0c;通过丰富内置算法&#xff0c;帮助用户快速、一站式地进行数据分析及挖掘建模&#xff0c;可应用于处理海量数据、高复杂性的数据挖掘任务&#xff0c;为其提供准确、高精度的计算…

大数据之数据模型

一、星型摸型 事实表是记录一个事实的&#xff0c;可以理解为订单表&#xff0c; 纬度表是提供更丰富信息的表&#xff0c;可以理解为商品明细表、订单明细表&#xff1b; 它是由一个事实表和一组维表组成&#xff0c;每个维表都有一个维作为主键&#xff0c;所有这些维的主键…

数据建模概述

数据建模&#xff08;data modeling&#xff0c;其实应该就是创建一个函数&#xff09;指的是对现实世界各类数据的抽象组织&#xff0c;确定数据库需管辖的范围、数据的组织形式等直至转化成现实的数据库。 将经过系统分析后抽象出来的概念模型转化为物理模型后&#xff0c;在…

大数据时代建模——图数据库建模

导读&#xff1a;云计算环境下&#xff0c;传统关系型数据库在海量数据存储方面存在瓶颈&#xff0c;对树形结构与半结构化数据的建模比较困难。本文介绍一种全新的建模方式——图数据库建模。应用图数据库模型更具扩展性、灵活性、高可靠性和高性能&#xff0c;能建立高细粒度…

大数据挖掘建模平台是怎样的?

大数据挖掘建模平台是可视化、一站式、高性能的数据挖掘与人工智能建模服务平台。面向企业级用户的大数据挖掘建模平台。平台采用可视化操作方式&#xff0c;通过丰富内置算法&#xff0c;帮助用户快速、一站式地进行数据分析及挖掘建模&#xff0c;可应用于处理海量数据、高复…

数据建模.

数据建模 什么是数据建模为什么要进行数据建模怎么进行数据建模 1. 为什么要进行数据建模&#xff1f; 提高 效率/性能&#xff1a; 计算机的的吞吐率&#xff0c;减少I/O的时间&#xff0c;提高用户使用数据的效率。开销&#xff1a;减少数据的冗余&#xff0c;从而节省存…

大数据数据建模

今天给大家分享一下 数据开发工作中数据建模的步骤&#xff0c; 第一步&#xff1a;选择模型或者自定义模型 这第一步需要我们基于业务问题&#xff0c;来决定我们需要选择哪种模型&#xff0c;目前市场中有很多模型可以供我们选择&#xff0c; 比如&#xff0c;如果要预测产…

数据建模

周三保(zhousbcn.ibm.com) IBM 软件部信息技术专家. 简介&#xff1a; 本文的主要内容不是介绍现有的比较流行的主要行业的一些数据模型&#xff0c;而是将笔者在数据仓库建设项目中的一些经验&#xff0c;在这里分享给大家。希望帮助大家在数据仓库项目建设中总结出一套能够合…

大数据分析及其建模利用

在数字经济时期&#xff0c;互联网、物联网、5G、大数据、智慧城市等各类模式的信息技术呈爆炸式增长&#xff0c;使得数据以令人难以设想的速度始终增长&#xff0c;企业运营的各个阶段都可以被记载下来&#xff0c;产品销售的各个环节也被记载下来&#xff0c;客户的生产行为…

浅谈大数据建模的主要技术:维度建模

文章目录 前言维度建模关键概念度量和环境事实和维度事实表维度表星形架构和雪花架构 维度建模一般过程1. 选取业务过程2. 定义粒度3. 确定维度4. 确定事实 前言 我们不管是基于 Hadoop 的数据仓库&#xff08;如 Hive &#xff09;&#xff0c;还是基于传统 MPP 架构的数据仓…

大数据建模五步法

from&#xff1a;https://www.sohu.com/a/198093510_783844 前一阵子&#xff0c;某网络公司发起了一个什么建模大赛&#xff0c;有个学员问我&#xff0c;数据建模怎么搞&#xff1f; 为了满足他的好学精神&#xff0c;我决定写这一篇文章&#xff0c;来描述一下数据分析必须…

大数据实践之数据建模

随着DT时代互联网、智能设备及其他信息技术的发展&#xff0c;数据爆发式增长&#xff0c;如何将这些数据进行有序、有结构地分类组织和存储是我们面临的一个挑战。 为什么需要数据建模 如果把数据看作图书馆里的书&#xff0c;我们希望看到它们在书架上分门别类地放置&#xf…

大数据之数据建模

1.星座模型 星形模型中有一张事实表&#xff0c;以及零个或多个维度表&#xff0c;事实表与维度表通过主键外键相关联&#xff0c;维度表之间没有关联&#xff0c;当所有维表都直接连接到“事实表”上时&#xff0c;整个图解就像星星一样。 星形模型是最简单&#xff0c;也是…

数据模型篇之大数据领域建模综述

第8章 大数据领域建模综述 1.为什么需要数据建模 为了更好的将数据进行有序、有结构地分类组织和存储。数据模型就是数据组织和存储方法&#xff0c;它强调从业务、数据存取和使用角度合理存储数据。 数据建模的好处&#xff1a; 性能&#xff1a;良好的数据模型能帮助我们快…

大数据学习(七)一分钟了解数据建模

何为大数据建模&#xff0c;我们从3个W&#xff08;什么、为什么、如何&#xff09;出发来详解下大数据建模。 一、什么是数据建模&#xff08;what&#xff09; 数据建模指的是对现实世界各类数据的抽象组织&#xff0c;确定数据库需管辖的范围、数据的组织形式等直至转化成…

[数学建模] 大数据建模五步法

目录传送门 概要第一步&#xff1a;选择模型或自定义模式第二步&#xff1a;训练模型第三步&#xff1a;评估模型第四步&#xff1a;应用模型第五步&#xff1a;优化模型最后语 概要 PS: 本文转载自 https://www.sohu.com/a/198093510_783844 本文将尝试来梳理一下数据建模的…

人工智能知识体系大全

知识的搬运工&#xff0c;转从https://blog.csdn.net/j2iayu7y/article/details/79709420 转自&#xff1a;https://blog.csdn.net/wyx100/article/details/80950499

史上最全的人工智能知识图谱

史上最全的人工智能知识图谱 转载于公众号&#xff1a; 数邦客 人工智能知识图谱 1 知识图谱 知识图谱(Knowledge Graph)又称为科学知识图谱&#xff0c;由Google与2012年5月提出&#xff0c;目的是提高搜索引擎的能力&#xff0c;改善用户的搜索质量及搜索体验。随着人工智能…