避免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

  1. class SubList<E> extends AbstractList<E>{
  2. private AbstractList<E> l;
  3. private int offset;
  4. private int size;
  5. //SubList类的构造方法
  6. SubList(AbstractList list, int fromIndex, int toIndex){
  7. //...
  8. l = list;
  9. offset = fromIndex;
  10. size = toIndex - fromIndex;
  11. //...
  12. }
  13. //...

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

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

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

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

避免使用subList/subString

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

  • 以subList为例:

    1. //...
    2. List<Integer> newList = new ArrayList<>();
    3. for(int i = begin; i < end; i++)
    4. {
    5. //原List为list
    6. newList.add(list.get(i));
    7. }
    8. //...
  • 另外,对于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. Bear and Three Balls

    链接:http://codeforces.com/problemset/problem/653/A                                                   ...

  2. Appium环境搭建(Windows版)

    Appium介绍 Appium是一个开源.跨平台的测试框架,可以用来测试原生及混合的移动端应用.Appium支持iOS.Android及FirefoxOS平台.Appium使用WebDriver的js ...

  3. Java面试题大全

    前言 关于赢在面试的Java题系列基本收集整理完成了,所有题目都是经过精心挑选的,很基础又考验求职者的基本功,应该说被面试到的几率很大.这里整理挑选出来供大家面试前拿来看一看,所有题目整理自网络,有一 ...

  4. 社交系统ThinkSNS+ 发布通知!

    社交系统ThinkSNS 最新版本ThinkSNS+将于7月15日正式发布开源版本web+H5,同时发布Android APP和iOS APP.我们将告别内测阶段,正式对外发布. 没错,你们没看错,就 ...

  5. Strace跟踪解决expect乱码问题

    --Strace跟踪解决expect乱码问题 ----------------------------------2014/07/27 情景:需要在本机抓去另外一台远程数据库中的数据. 执行语句:./ ...

  6. OpenGL与CUDA互操作方式总结

    一.介绍 CUDA是Nvidia推出的一个通用GPU计算平台,对于提升并行任务的效率非常有帮助.本人主管的项目中采用了OpenGL做图像渲染,但是在数据处理方面比较慢,导致帧率一直上不来.于是就尝试把 ...

  7. OS作业模拟SJF和FCFS

    一个OS的作业, 用于模拟短作业优先 和 先来先服务两种作业调度方式. #!/usr/bin/python3.5 ## Modify the SJF and FCFS algorithm in the ...

  8. postman也可以使用F12功能

    背景: 做过接口测试的话,大多数都知道或使用过postman工具,使用postman的时候,有时候希望也可以像chrome一样使用F12功能,这样方便观察一些数据,尤其是当你使用了postman的变量 ...

  9. 一起来学Go --- (go的变量)

    变量 变量是几乎所有编程语言中最基本的组成元素,从根本上说,变量相当于是一块数据存储空间的命名,程序可以通过定义一个变量来申请一块数据存储空间,之后可以通过引用变量名来使用这块存储空间.go语言中的变 ...

  10. 50行Python代码构建小型区块链

    本文介绍了如何使用python构建一个小型的区块链技术,使用Python2实现,代码不到50行. Although some think blockchain is a solution waitin ...