【问题标题】:Understanding StringUtils.join performance decisions了解 StringUtils.join 性能决策
【发布时间】:2016-09-12 05:43:53
【问题描述】:

我正在查看 Apache Commons 的 StringUtils.join 方法的实现,偶然发现了一条我认为是为了提高性能的行,但我不明白他们为什么按照这些特定值这样做。

下面是实现:

public static String join(Object[] array, String separator, int startIndex, int endIndex) {
    if (array == null) {
        return null;
    }
    if (separator == null) {
        separator = EMPTY;
    }

    // endIndex - startIndex > 0:   Len = NofStrings *(len(firstString) + len(separator))
    //           (Assuming that all Strings are roughly equally long)
    int noOfItems = (endIndex - startIndex);
    if (noOfItems <= 0) {
        return EMPTY;
    }

    StringBuilder buf = new StringBuilder(noOfItems * 16); // THE QUESTION'S ABOUT THIS LINE

    for (int i = startIndex; i < endIndex; i++) {
        if (i > startIndex) {
            buf.append(separator);
        }
        if (array[i] != null) {
            buf.append(array[i]);
        }
    }
    return buf.toString();
}

我的问题是关于StringBuilder buf = new StringBuilder(noOfItems * 16); 行:

  • 我假设为StringBuilder 提供初始容量目标性能,因此在构建字符串时需要较少的调整大小。我的问题是:这些调整大小操作实际上对性能有多大影响?这种策略真的能在速度方面提高效率吗? (因为就空间而言,如果分配的空间超出必要,甚至可能是负数)
  • 为什么要使用幻数16?为什么他们会假设数组中的每个 String 都是 16 个字符长?这个猜测有什么用?

【问题讨论】:

  • 我不知道,但我猜 16 只是对平均预期大小的猜测。听起来很适合我通常需要它的用例。请记住,StringBuilder 无论如何都会被 GC 处理,所以它是否有点太大也没关系。节省调整大小很好,因为调整大小需要复制整个先前的数组;在最坏的情况下,如果您每次都调整大小,那么您将获得 o(n^2) 的性能。

标签: java string performance apache-stringutils


【解决方案1】:

16 略微高估了带分隔符的字符串的预期平均大小(可能基于经验/统计数据)。

预先分配足够的空间来保存整个结果可以避免在执行期间用更大(两倍大小)的数组替换后备数组并复制元素(这是一个 O(n) 操作)。

如果在大多数情况下避免替换操作,那么高估,即使是相当多的,分配一个更大的数组也是值得的。

【讨论】:

    【解决方案2】:

    真的...这不是您在问题中所说的硬编码的唯一 16

    如果您再次查看定义。你会发现类似的东西。

    bufSize *= ((array[startIndex] == null ? 16 : array[startIndex].toString().length())
                            + separator.length());  
         //16 will only assigned if Object array at position StartIndex contains null.
    
            StringBuffer buf = new StringBuffer(bufSize); //if null then default memory allocation for String Buffer will be 16 only.
    

    这里StringBuffer会调用appriviates as的构造函数

         new StringBuffer(int Capacity);
    Constructs a string buffer with no characters in it and the specified initial capacity.
    

    如果对象数组包含位于索引startIndex 的元素,则默认内存分配将是该Objectlength

    谢谢。

    【讨论】:

      【解决方案3】:

      hmm.. StringUtils.join 在大数组中生成 OutOfMemory Exception...; 你知道这种情况。

      【讨论】:

        猜你喜欢
        • 2018-03-03
        • 2020-08-05
        • 2017-06-05
        • 2011-06-28
        • 2016-08-05
        • 2019-07-25
        • 1970-01-01
        • 2013-07-12
        • 1970-01-01
        相关资源
        最近更新 更多