避免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. 使用Jexus 5.8.2在Centos下部署运行Asp.net core

    这里安装的Jexus不是独立版本,所以需要先安装Mono   系统版本:Cenos7,Mono版本:5.0.1 Stable (5.0.1.1) Mono官方doc:http://www.mono-p ...

  2. Unity 发布的 WenGL 使用SendMessage传递多个参数

    如果要实现Unity与浏览器的数据交互一般都会采用两种方式 方法一: Application.ExternalCall("SayHello","helloworld&qu ...

  3. 百度之星2017初赛A轮 1001 小C的倍数问题

    小C的倍数问题 Accepts: 1990 Submissions: 4931 Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 32768/3 ...

  4. H5滚动轮播插件

      概述 JRedu 随着前端技术的发展,越来越多的H5技术被应用到实际开发中,尤其是js插件更是无处不用,本章节我们主要分享下如何去自己封装一个滚动轮播插件. 1效果图如下: 2主要功能   支持超 ...

  5. Git 深入浅出

    如果你是一个开发人员,想用上这个世界上目前最先进的分布式版本控制系统,那么,赶快开始学习吧!(耐心读下去,收获满满) Git是什么? Git是目前世界上最先进的分布式版本控制系统(没有之一). Git ...

  6. react-native学习路线总结

    本人新手web前端程序员一枚,应公司要求学习React-native框架,作为博客萌新来讲讲我这一个月学习历程,新人和前端的朋友们可以一看,其他都可看,反正不用你掏钱啊. 首先当然还是介绍一下reac ...

  7. 配置Tomcat

    目前有很多网站使用jsp的程序编写,所以解析jsp的程序就必须要有相关的软件来完成.Tomcat就是用来解析jsp程序的一个软件. 安装tomcat Tomcat的安装分为两个步骤:安装JDK和安装T ...

  8. javascript多种方法实现数组去重

    先说说这个实例的要求:写一个方法实现数组的去重.(要求:执行方法,传递一个数组,返回去重后的新数组,原数组不变,实现过程中只能用一层循环,双层嵌套循环也可写,只做参考): 先给初学者解释一下什么叫数组 ...

  9. meta标签的name和http-equiv属性

    META标签是HTML语言HEAD区的一个辅助性标签,它位于HTML文档头部的<HEAD>标记和<TITLE>标记之间,它提供用户不可见的信息.META标签有两个重要的属性:H ...

  10. 记录git常用操作命令

    GIT的常用操作 0.写在前面 作为一名开发者,熟悉使用 git 代码管理工具是一项必备的基本技能.git 相较 SVN 而言,其优点不言而喻.git 的功能非常强大,其包括的操作命令也非常的多,但是 ...