了解 StringUtils.join 绩效决策
Understanding StringUtils.join performance decisions
我正在查看 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
一个初始容量目标性能,因此在构建字符串时需要较少的调整大小。我的问题是:这些调整大小操作实际上对性能有多大影响?这种策略真的在速度方面提高了效率吗? (因为就 space 而言,如果分配的 space 多于必要的数量,它甚至可能是负数)
- 为什么要使用幻数
16
?为什么他们会假设数组中的每个 String
都是 16 个字符长?这个猜测有什么用?
真的...这不仅仅是您在问题中所说的硬编码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
会调用指定为
的构造函数
new StringBuffer(int Capacity);
Constructs a string buffer with no characters in it and the specified initial capacity.
如果对象数组包含索引 startIndex
处的元素,则默认内存分配将为 Object
的 length
。
谢谢。
16
略微高估了带分隔符的字符串的预期平均大小(大概基于 experience/statistics)。
预先分配足够的 space 来保存整个结果,避免在执行期间用更大(双倍大小)的数组替换支持数组并复制元素(这是一个 O(n) 操作) .
如果在大多数情况下避免替换操作,分配更大的数组是值得的,即使是相当多的估计也是值得的。
嗯.. StringUtils.join
在大数组中制作 OutOfMemory Exception
...;
你知道这种情况。
我正在查看 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
一个初始容量目标性能,因此在构建字符串时需要较少的调整大小。我的问题是:这些调整大小操作实际上对性能有多大影响?这种策略真的在速度方面提高了效率吗? (因为就 space 而言,如果分配的 space 多于必要的数量,它甚至可能是负数) - 为什么要使用幻数
16
?为什么他们会假设数组中的每个String
都是 16 个字符长?这个猜测有什么用?
真的...这不仅仅是您在问题中所说的硬编码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
会调用指定为
new StringBuffer(int Capacity);
Constructs a string buffer with no characters in it and the specified initial capacity.
如果对象数组包含索引 startIndex
处的元素,则默认内存分配将为 Object
的 length
。
谢谢。
16
略微高估了带分隔符的字符串的预期平均大小(大概基于 experience/statistics)。
预先分配足够的 space 来保存整个结果,避免在执行期间用更大(双倍大小)的数组替换支持数组并复制元素(这是一个 O(n) 操作) .
如果在大多数情况下避免替换操作,分配更大的数组是值得的,即使是相当多的估计也是值得的。
嗯.. StringUtils.join
在大数组中制作 OutOfMemory Exception
...;
你知道这种情况。