避免subList/subString陷阱

  • java.util.List 接口提供了一个实例方法 List<E> subList(int fromIndex, int toIndex), 用于截取 原List 的一个以 fromIndex 为起始索引,以 toIndex 为终止索引(不包括)的子列表。
  • subString 类似于 subList ,对 String 进行截取。

subList/subString陷阱

subString在本文涉及到的方面都类似于subList,不再赘述

关于函数返回值使用的陷阱

subList的实现代码在AbstractList类里,返回AbstractList的一个子类SubList

class SubList<E> extends AbstractList<E>{
private AbstractList<E> l;
private int offset;
private int size; //SubList类的构造方法
SubList(AbstractList list, int fromIndex, int toIndex){
//...
l = list;
offset = fromIndex;
size = toIndex - fromIndex;
//...
} //...

根据以上代码,我们知道,SubList将原来的list赋值给了l,只是改变了偏移量offset。也就是说,subList函数返回了原始list对象的引用

这也就意味着,对原list和返回的list做的“非结构性修改”(指不涉及list大小改变的修改),都会影响到彼此。

//对返回的list排序,观察原list
public static void main(String[] args)
{
Scanner sc = new Scanner(System.in);
List<Integer> list = new ArrayList<>();
while(sc.hasNextInt())
{
list.add(sc.nextInt());
}
List<Integer> subList = new ArrayList<>();
subList = list.subList(0, list.size());
subList.sort(null);
for(int i = 0; i < list.size(); i++)
System.out.print(list.get(i) + " ");
sc.close();
}
//输入:
1 3 2 5 4
//输出:
1 2 3 4 5

OOM问题

看到这里读者可能会产生疑问,为什么要用原list的引用作为返回值?

原因在于,这种实现可以提高运行时的性能;

如果创建一个新的list,然后添加所需的内容,这种实现方法无论从内存消耗还是从运行效率来看都远不如直接引用原始list、设置offset和size的方法。

然而,这种返回引用的方法可能会引起一个更加麻烦且难发现的错误:out of memory

在SubList中,保存了原list的强引用,这意味着,在jvm进行垃圾回收时,只要有一个这样的SubList没有被回收,原List就不会被回收,从而占用这内存空间。当我们只需要长时间保留原List中的一小段数据,却用了subList,而除了SubList中的引用之外,没有其他的引用指向原List,这种情况下,就会造成严重的内存空间的浪费。

可想而知,当这样的subList足够多,jvm没办法及时回收,这些subList就会吃掉所有内存。

如何避免陷阱

正确使用subString/subList

  • subList/subString适合处理局部的List/String时,比如删除局部的List :

    list.subList(begin, end).clear();
  • subList/subString的一个明显优势在于提高了运行的性能,不用进行冗长的复制过程。所以,如果对程序的性能要求高,可以考虑用subString/subList。

避免使用subList/subString

如果有截取整体中较小的一段来做操作而不改变原整体的需要,或有截取一小段长期保存在内存中的需要

  • 以subList为例:

    //...
    List<Integer> newList = new ArrayList<>();
    for(int i = begin; i < end; i++)
    {
    //原List为list
    newList.add(list.get(i));
    }
    //...
  • 另外,对于String,可以用new String()来构造一个新的String来复制需要的部分。

update by 2017/3/30 19:33

by 一棵球

避免subList/subString陷阱的更多相关文章

  1. 需要注意的subList方法!和substring是不一样的!从源码解释他们的不同。

    很多时候我们截取字符串用的是substring方法,很自然用着,但是对于列表的截取时很多时候就用得很少,但是其实他们是很不一样的,具体哪里不一样呢? package main; import java ...

  2. java List.subList方法中的超级大陷阱

    ArrayList 中 subList 的基本用法: subList(fromIndex:int,toIndex:int):List<E> 返回从fromIndex到toindex-1 的 ...

  3. Java提高配(三七)-----Java集合细节(三):subList的缺陷

    我们经常使用subString方法来对String对象进行分割处理,同时我们也可以使用subList.subMap.subSet来对List.Map.Set进行分割处理,但是这个分割存在某些瑕疵. 一 ...

  4. 1. Longest Palindromic Substring ( 最长回文子串 )

    要求: Given a string S, find the longest palindromic substring in S. (从字符串 S 中最长回文子字符串.) 何为回文字符串? A pa ...

  5. subList和asList

    subList subList返回仅仅只是一个视图.直接上源码 public List<E> subList(int fromIndex, int toIndex) { subListRa ...

  6. Java(jdk1.7) 陷阱

    String[] strA = new String[4]; for(int i=0; i<4; i++) { strA[i] = String.valueOf(i); } strA[0] = ...

  7. Javascript 判断变量类型的陷阱 与 正确的处理方式

    Javascript 由于各种各样的原因,在判断一个变量的数据类型方面一直存在着一些问题,其中最典型的问题恐怕就是 typeof null 会返回 object 了吧.因此在这里简单的总结一下判断数据 ...

  8. 集合之subList的缺陷

    我们经常使用subString方法来对String对象进行分割处理,同时我们也可以使用subList.subMap.subSet来对List.Map.Set进行分割处理,但是这个分割存在某些瑕疵. 一 ...

  9. subString引起的index out of range

    特别注意!!!低级坑 subString(begin,end)   subList()均存在这个问题. 当end>String.size(),则index out of range!!!

随机推荐

  1. 【HTTP权威指南】第二章-URL与资源

    [统一资源定位符URL]通过位置来标示资源,其表达的格式如下:https://item.jd.com/523961.html 第一部分(https)是方案,告知客户端要[怎样访问],这里使用的是htt ...

  2. [bzoj 1409] Password 矩阵快速幂+欧拉函数

    考试的时候想到了矩阵快速幂+快速幂,但是忘(bu)了(hui)欧拉定理. 然后gg了35分. 题目显而易见,让求一个数的幂,幂是斐波那契数列里的一项,考虑到斐波那契也很大,所以我们就需要欧拉定理了 p ...

  3. Linux 日常常用指令

    最近搞了一个阿里ECS,CentOS7,涉及到一些基本的Linux指令,在这里总结一下,在搭环境中常用的一些指令,熟悉这些指令就基本能够使用CentOS进行日常操作了. 更多的可以参考系统自带的  “ ...

  4. 使用 Node.js 搭建一个 API 网关

    原文地址:Building an API Gateway using Node.js 外部客户端访问微服务架构中的服务时,服务端会对认证和传输有一些常见的要求.API 网关提供共享层来处理服务协议之间 ...

  5. 【NO.6】HTTP请求-配置-POST请求-GET请求

    直接举例来说 :) 例1:URL里面有”&”连接的情况 http://123.456.7.89:8080/aa/bb/cc/?userid=abcd@gmail.com&operati ...

  6. 解决Coursera视频无法观看

    修改电脑的 C:\Windows\System32\drivers\etc 目录下的host文件, 在最后添加一行: 52.84.246.72 d3c33hcgiwev3.cloudfront.net

  7. MSPointerEvent属性

    MSPointerEvent属性 属性 描述 hwTimestamp 创建事件的时间(ms) isPrimary 标识该指针是不是主指针 pointerId 指针的唯一ID(类似于触摸事件的标识符) ...

  8. PHP魔术方法

    魔术方法:两个下划线开头的格式. PHP中的魔术方法总结 :__construct, __destruct , __call, __callStatic,__get, __set, __isset, ...

  9. 一句话搞定-phpStudy安装yaf扩展

    首先下载phpStudyX64位的,然后傻瓜式安装,安装完下载yaf,由于yaf扩展的网站在国外很难下载,需要FQ,所以我这里下载了yaf5.6nts.zip,解压后把php_yaf.dll这个文件粘 ...

  10. java --jfree报表

    ---恢复内容开始--- 1.使用的报表工具: jfree报表 2.下载网址: http://www.jfree.org/ 下载之后先解压:如下图 下载后:需要的jar包!如下图: 打开:找到以下的两 ...