2019独角兽企业重金招聘Python工程师标准>>>

  • 本文是本人的学习笔记,把自己的理解总结记录下来。因本人水平有限,如果您在阅读中发现错误,还望谅解,并且希望能够告知本人改正,不胜感激!

  • ArrayList中的subList()方法

    ArrayList中的subList(int fromIndex, int toIndex)方法,是返回当前ArrayList中从索引为fromIndex的位置索引位置为toIndex-1的位置的列表 视图。这里需要注意几点:

    1. subList方法传入的参数是左闭右开的,也就是[formIndex,toIndex)的形式。所以如果传来两个相同的index进去会返回一个空的列表。

      public class SubListTest {public static void main(String[] args) {List<String> list = new ArrayList<String>();list.add("1");list.add("2");list.add("3");list.add("4");List<String> subList = list.subList(1, 1);System.out.println("subList: " + subList); // subList: []}
      }
      
    2. subList方法返回的只是一个视图,是一个对源列表的映射。这意味着如果对subList返回的列表进行编辑操作,源列表也会收到影响。

    3. 对subList方法返回的列表进行添加、删除元素会抛出异常。

       public class SubListTest { public static void main(String[] args) { List<String>; list = new ArrayList<String>(); list.add("1"); list.add("2")list.add("3");list.add("4");List<String> subList = list.subList(0, 2); System.out.println(subList);list.remove(1);System.out.println("subList:" + subList); System.out.println("list:" + list); } }
    

    抛出异常:

    Exception in thread "main"  java.util.ConcurrentModificationExceptionat 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.lijunpeng.List.SubListTest.main(SubListTest.java:23)
    

    这是因为触发fail-fast机制,导致抛出异常,关于fail-fase机制,可以参见这篇博客:Java中的fail-fast机制

  • subList方法的源码

    public List<E> subList(int fromIndex, int toIndex) {// 判断参数的合法性subListRangeCheck(fromIndex, toIndex, size);// 返回一个SubList实例return new SubList(this, 0, fromIndex, toIndex);
    }
    

    该方法会返回一个SubList的实例,SubList是一个ArrayList的内部类,其构造方法如下:

        // SubList中的属性private final AbstractList<E> parent;private final int parentOffset;private final int offset;int size;// 构造方法SubList(AbstractList<E> parent,int offset, int fromIndex, int toIndex) {this.parent = parent;this.parentOffset = fromIndex;this.offset = offset + fromIndex;this.size = toIndex - fromIndex;// 这个参数就是触发fail-fast机制的关键this.modCount = ArrayList.this.modCount;}
    

    可以看到,SubList中并没有数组、列表之类的属性来存储数据,这进一步说明了,subList方法返回的只是一个视图。 之前说过,对subList方法返回的列表进行修改,源列表也会跟着发生变化,下面是SubList的set方法

        public E set(int index, E e) {// 传入的参数索引合法性校验rangeCheck(index);// 这个方法就是用来检验modCount从而触发fail-fast机制,// 但是set这里modCount不会发生变化,所以不会触发fial-fast机制checkForComodification();// 从外部类(源列表)获取值E oldValue = ArrayList.this.elementData(offset + index);// 讲外部类(源列表)的值替换成新的值,ArrayList的值是存在elementData的数组中的。ArrayList.this.elementData[offset + index] = e;return oldValue;}
    

    从上面代码看出,修改subList的值其实是在修改源列表的值的,所以源列表值发生变化是必然的。 接下来再看一下为什么在源列表中删除或添加会抛出异常呢,首先我们先看一下之前报错的信息:

        Exception in thread "main" java.util.ConcurrentModificationExceptionat 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.lijunpeng.List.SubListTest.main(SubListTest.java:23)

首先报错的是main函数的23也就是:System.out.println("subList:" + subList) 这一句。这一步并没有操作subList,是调用了其toString方法,进一步调用了SubList的迭代器方法。所以需要往下看错误信息,发现在checkForComodification这个方法中报错,上面在set方法中也有这个方法,并且这个方法就是触发java的fail-fast机制。所以看一下这个checkForComodification方法的代码:

    private void checkForComodification() { if (ArrayList.this.modCount != this.modCount) throw new ConcurrentModificationException(); }

checkForComodificatio中比较了SubList类中的modCount和外部类ArrayList中的modCount是否相等,不相等就会抛出ConcurrentModificationException,触发fail-fast机制。那为什么这两个modeCount不相等呢?首先需要再回顾一下SubList类中的构造函数:

      // SubList的构造函数 SubList(AbstractList parent, int offset, int fromIndex, int toIndex) {this.parent = parent; this.parentOffset = fromIndex; this.offset = offset + fromIndex; this.size = toIndex - fromIndex; // 在构造时,SubList中的modCount和ArrayList中的modCount是一致的 this.modCount = ArrayList.this.modCount; }

接着,看一下ArrayList中的add方法,注意:代码中调用的是list.add而不是subList.add,所以需要看ArrayList的add源码:

    public boolean add(E e) {ensureCapacityInternal(size + 1);elementData\[size++\] = e;return true;}private void ensureCapacityInternal(int minCapacity) {ensureExplicitCapacity(calculateCapacity(elementData, minCapacity));}private void ensureExplicitCapacity(int minCapacity) { // 这里ArrayList的modCount发生了变化!modCount++;if (minCapacity - elementData.length > 0)grow(minCapacity);}

示例代码中:在list.add("5"),之后就直接打印了,也就是说我们没有再对SubList进行操作,SubList中的modCount也没有发生改变,所有 ArrayList.this.modCount != this.modCount 成立,导致抛出了ConcurrentModificationException异常。这里不仅打印会抛出异常,只要对subList进行操作都会抛出,因为SubList的方法都进行了checkForComodificatio,检查这两个modCount。

但是如果只对subList方法返回的列表:subList进行增删元素的操作,并不会抛出异常,但是同样会影响源列表,因为subList的所有操作都是在操作源列表:

    public class SubListTest {public static void main(String[] args) {List<String> list = new ArrayList<String>();list.add("1");list.add("2");list.add("3");list.add("4");    List&lt;String&gt; subList = list.subList(0, 2);System.out.println(subList);subList.add("3");System.out.println("subList:" + subList); // subList:[1, 2, 3]System.out.println("list:" + list); // list:[1, 2, 3, 3, 4]}}
  • 如果想要对subList的操作,可以新建一个ArrayList,将subList addAll进这个新的列表,从而操作这一个新的列表。
 public class SubListTest {public static void main(String[] args) {List<String> list = new ArrayList<String>();list.add("1");list.add("2");list.add("3");list.add("4");List<String> subList = list.subList(0, 2);List<String> newList = new ArrayList<String>();newList.addAll(subList);newList.set(0, "new1");System.out.println("list:" + list); // list:[1, 2, 3, 4]System.out.println("subList:" + subList); // subList:[1, 2]System.out.println("newList:" + newList); // newList:[new1, 2]}}
  • 小结

    • ArrayList.subList方法返回的只是视图
    • subList的所有操作都是在操作源列表ArrayList,所以增删改都会以影响源列表。
    • 对ArrayList进行添加、删除的操作之后,在操作subList会抛出异常
    • 仅仅subList操作并不会抛出异常

转载于:https://my.oschina.net/u/3428296/blog/1838962

java ArrayList中的subList方法相关推荐

  1. java list sublist方法_聊聊ArrayList中的subList方法

    开发过程中遇到的坑 开发过程经常会使用subList做分页处理. 比如下面的代码 while(pageIndex < maxSize) { List temp = userIds.subList ...

  2. 原创 | 为什么阿里巴巴要求谨慎使用ArrayList中的subList方法

    △Hollis, 一个对Coding有着独特追求的人△ 这是Hollis的第 219 篇原创分享 作者 l Hollis 来源 l Hollis(ID:hollischuang) 集合是Java开发日 ...

  3. 使用ArrayList中的subList方法

    集合是Java开发日常开发中经常会使用到的.在之前的一些文章中,我们介绍过一些关于使用集合类应该注意的事项,如<为什么阿里巴巴禁止在 foreach 循环里进行元素的 remove/add 操作 ...

  4. java sublist_java中List.subList()方法的使用

    sublist返回的东西,官方解释:Returns a view of the portion of this list between the specified fromIndex, inclus ...

  5. Java中的subList方法

    Java中的subList方法 今天看到了java中List中有个subList的方法,感觉很熟悉有没有?没错,在Stirng类中,也有个类似的方法:subString. Stirng中的subStr ...

  6. Java ArrayList中retainAll()方法具有什么功能呢?

    转自: Java ArrayList中retainAll()方法具有什么功能呢? 下文笔者讲述java中ArrayList方法的功能简介说明,如下所示: retainAll()方法的功能:用于保留 a ...

  7. 编写高质量代码:改善Java程序的151个建议 (第1章 Java开发中通用的方法和准则)

    第1章 Java开发中通用的方法和准则 The reasonable man adapts himself to the world;the unreasonable one persists in ...

  8. java多线程中的join方法详解

    java多线程中的join方法详解 方法Join是干啥用的? 简单回答,同步,如何同步? 怎么实现的? 下面将逐个回答. 自从接触Java多线程,一直对Join理解不了.JDK是这样说的:join p ...

  9. Shell-通过shell启动Java类中的main方法 + 通过Shell启动jar包

    文章目录 概述 shell启动Java类中的main方法 启动脚本分析 启动脚本 shell启动jar包 概述 Java程序 运行在linux主机上, 通过shell脚本启动为进程. Java程序中 ...

最新文章

  1. SAP S4HANA里委外加工采购功能的变化
  2. vue + webpack 模拟后台数据
  3. python爬虫获取的网页数据为什么要加[0-使用 Python 爬取网页数据
  4. php做通讯录界面,PHP 制作通讯录(三)
  5. 测试框架之GTest
  6. 探索比特币源码6-公钥
  7. mobaxterm怎么解除sessions个数限制_详解Oracle实例囚笼--限制数据库实例使用的CPU资源...
  8. 做自媒体花式撸收益?
  9. 分享一个四两拨千斤的真实故事
  10. 有人说苹果手机的CPU非常强大,为什么会这样?苹果cpu又是谁设计的?
  11. 【渝粤题库】陕西师范大学200081中国古代文学(一)作业(高起本、高起专)
  12. Win7系统怎么开启远程桌面?Win7远程桌面怎么用
  13. joomla新建模板_WordPress v Joomla:模板和主题
  14. 百度和今日头条正式开战
  15. 职场中为人处世那些事!
  16. maven项目转gradle
  17. Windows安装达梦数据库(Intel CPU)
  18. 使用snap安装mosquitto并且进行初步配置
  19. aspose 换行写_Aspose.Words对于Word的操作
  20. 派斯宝多尼斯荣登纳斯达克大屏 闪耀国际舞台

热门文章

  1. sunplus8202v 无线游戏手柄——续
  2. 串行舵机/数字舵机的替代方案,低成本的舵机级联方案。数字舵机的驱动芯片。普通舵机改数字舵机
  3. linux下文本文件转换编码格式的方法
  4. 英语总结系列(二十七):重复就是力量
  5. Google开放最大目标检测数据集,还要为它举办AI挑战赛
  6. 百度发起机器阅读理解竞赛,提供中文数据集,获胜团队奖10万
  7. Tideways+Xhgui搭建非侵入式php监控平台
  8. 360分拆计划生变,临时剥离四大业务
  9. 微信小程序第三方平台和附近的小程序将开放
  10. mysql innodb_double_write特性