避免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. ABP+AdminLTE+Bootstrap Table权限管理系统第十节--AdminLTE模板菜单处理

    上节我们把布局页,也有的临时的菜单,但是菜单不是应该动态加载的么?,所以我们这节来写菜单.首先我们看一下AdminLTE源码里面的菜单以及结构. <aside class="main- ...

  2. h5 录音

    得益于前辈的分享,做了一个h5录音的demo.效果图如下: 点击开始录音会先弹出确认框: 首次确认允许后,再次录音不需要再确认,但如果用户点击禁止,则无法录音: 点击发送 将录音内容发送到对话框中.点 ...

  3. js获取url,截取url参数,截取url后文件名

    获取当前: var url = window.location.href; 百度为例: var url=window.location.href; console.info(url); http:// ...

  4. RabbitMQ教程(一)——安装配置

    RabbitMQ教程(一)——安装配置 一.前言 由于最近在学习RabbitMQ消息队列,但是鉴于网上对于官网介绍的教程比较少或者由于时间长长期未更新,因此决定将对官网的RabbitMQ入门教程进行翻 ...

  5. 纯JSP实现用户登录注册,记事本

    没有美化,没有格式,没有样式 1.JSP登陆注册 将用户注册的信息保存在application对象中,用于登录时的验证. 首页如下: 如果未登录,在  session 中找不到 currentUser ...

  6. noip提高组1999 导弹拦截

    导弹拦截 背景 实中编程者联盟为了培养技术精湛的后备人才,必须从基础题开始训练. 描述 某国为了防御敌国的导弹袭击,研发出一种导弹拦截系统.但是这种导弹拦截系统有一个缺陷:虽然它的第一发炮弹能够到达任 ...

  7. C# 移动无标题栏窗体的几种方法

    第一种,手工移动. 该方法根据鼠标位置实现窗体的移动.网上有很多相关的例子,这里不再多讲. 第二种,调用系统API原理:是当鼠标左键按下时,让系统认为是在标题栏按下的.这里我们用到了winapi里的W ...

  8. 菜鸟的Xamarin.Forms前行之路——按钮的按下抬起事件的监控(可扩展至其他事件)

    提问:监控按钮的点击事件,可以通过按钮的Click事件,或者Command绑定,那么如何监控按钮的按下与抬起,或者移动,长按,双击等事件? 解决方法:各个平台自定义渲染依赖注入. 共享项目PCL: 1 ...

  9. Linux下自动备份MySQL数据库并上传到远程FTP服务器

    Linux下自动备份MySQL数据库并上传到远程FTP服务器且删除指定日期前的备份Shell脚本 说明:  1.备份MySQL数据库存放目录/var/lib/mysql下面的xshelldata数据库 ...

  10. 实操代码研究各种Java技术-java.toutiao.im

    whatsmars https://github.com/javahongxi/whatsmars whatsmars-earth-web springmvc+velocitywhatsmars-ea ...