• 你了解Java中String的substring函数吗?


    你了解Java中String的substring函数吗?

    Java中的substring函数是我们经常使用的一个函数,用来截取当前字符串的子串,定义如下:

    public final class String{
        public String substring(int beginIndex);
        public String substring(int beginIndex, int endIndex);
    }

    使用及声明都非常简单,但是你了解其中的细节吗?

    我们再看一下substring的实现:

     1 public String substring(int beginIndex, int endIndex) {
     2         if (beginIndex < 0) {
     3             throw new StringIndexOutOfBoundsException(beginIndex);
     4         }
     5         if (endIndex > count) {
     6             throw new StringIndexOutOfBoundsException(endIndex);
     7         }
     8         if (beginIndex > endIndex) {
     9             throw new StringIndexOutOfBoundsException(endIndex - beginIndex);
    10         }
    11         return ((beginIndex == 0) && (endIndex == count)) ? this :
    12             new String(offset + beginIndex, endIndex - beginIndex, value);
    13 }

    在第12行返回了一个新的字符串,传入了三个参数:offset,count,以及原来String对象的value(char[])。

    继续看第12行String的构造函数:

    String(int offset, int count, char value[]) {
            this.value = value;
            this.offset = offset;
            this.count = count;
    }

    这是一个Package内部的方法,非public,注意他直接将传入的char[]给抓住了,定义了起始位置,以及长度。

    我理解他设计的初衷是为了节省内存,新的字符串还依然抓着老的字符串value的引用,只是重新定义起始位置和长度

    再补充一下String类的字段声明,可以看得更清楚一点:

    public final class String{
       /** The value is used for character storage. */
        private final char value[];
    
        /** The offset is the first index of the storage that is used. */
        private final int offset;
    
        /** The count is the number of characters in the String. */
        private final int count;
    
        /** Cache the hash code for the string */
        private int hash; // Default to 0
    }

    ---------------------------------------------

    华丽的分割线下是我的使用场景:

    逐行读取一个非常大的文本文件,每一行的长度比较大,提取其中的小部分(使用了substring函数),大约每行提取10个字,行数很多(整个文本可能会有几十M或更多)。

    读取文件完毕后我理解的内存消耗不会很大,但是完全出乎我的想象,内存消耗很大,甚至会outofmemory.

    我的代码:

    List<String> results = new ArrayList<String>();
    InputStream stream = new FileInputStream(filePath);
    BufferedReader bufferredReader = new BufferedReader(
                    new InputStreamReader(stream));
    while (true) {
        String line = bufferredReader.readLine();
    if (line == null) {
                    break;
        }
    results.add(line.substring(
    10, 20)); }

    Why?在查看了String的substring函数以及多方Google之后,终于明白了。

    原来新构建的String依然抓着每一行的文本,只是调整了offset和length,不是我们所理解的只抓着一个小文本,原来的长文本被GC回收这么回事。

    怎么办呐?只需要改一句:

    List<String> results = new ArrayList<String>();
    InputStream stream = new FileInputStream(filePath);
    BufferedReader bufferredReader = new BufferedReader(
                    new InputStreamReader(stream));
    while (true) {
        String line = bufferredReader.readLine();
        if (line == null) {
                    break;
        }
    
        results.add(new String(line.substring(10, 20)));
    }

    构建一个新的String,将字串传入,这样与原始字符串就没有关系了。所以在使用substring的时候,必须要注意使用场景。

    最后再提醒一个,String的split函数返回的子串也是如此。

  • 相关阅读:
    大型网站架构演化发展历程
    用Haproxy给MySQL做负载均衡
    一致性hash和虚拟节点
    Apache + Tomcat +mod_jk 实现集群
    浅谈时钟的生成(js手写代码)
    javascript
    vue-cli中安装方法
    webstorm激活
    解决webstorm卡顿问题
    gulp前端自动化环境搭建详解
  • 原文地址:https://www.cnblogs.com/tedzhao/p/Java_String_substring.html
Copyright © 2020-2023  润新知