为什么 StringBuffer#append 抛出 StringIndexOutOfBoundsException

Why StringBuffer#append throws StringIndexOutOfBoundsException

我有尝试附加 2 个 SttringBuffers 的代码:

logBuf.append(errStrBuf);

在日志中我看到以下跟踪:

java.lang.StringIndexOutOfBoundsException: String index out of range: 90
    at java.lang.AbstractStringBuilder.getChars(AbstractStringBuilder.java:325)
    at java.lang.StringBuffer.getChars(StringBuffer.java:201)
    at java.lang.AbstractStringBuilder.append(AbstractStringBuilder.java:404)
    at java.lang.StringBuffer.append(StringBuffer.java:253)

我无法理解问题的原因。

你能提供常量的例子吗?

会不会和并发有关?

你能提出解决方案吗?

是的,它可能与并发有关。根据 doc:

This method synchronizes on this (the destination) object but does not synchronize on the source (sb).

因此,如果在此过程中更改errStrBuf,则可能会产生此错误。自己同步,这样:

synchronize (errStrBuf) {
   logBuf.append(errStrBuf);
}

无论 errStrBuf 发生什么变化,都使用相同的同步块。

一些关于 Java 来源的搜索显示 StringBuffer.append(StringBuffer sb) 代表 AbstractStringBuilder.append(StringBuffer sb) 这样做:

    // Length of additional sb.
    int len = sb.length();
    // Make sure there's room.
    ensureCapacityInternal(count + len);
    // Copy them through.
    sb.getChars(0, len, value, count);

StringBuffer.getChars 再次委托给 AbstractStringBuilder 所以 getChars 看起来有点像:

public void getChars(int srcBegin, int srcEnd, char[] dst, int dstBegin)
{
    if (srcBegin < 0)
        throw new StringIndexOutOfBoundsException(srcBegin);
    if ((srcEnd < 0) || (srcEnd > count))
        throw new StringIndexOutOfBoundsException(srcEnd);
    if (srcBegin > srcEnd)
        throw new StringIndexOutOfBoundsException("srcBegin > srcEnd");
    System.arraycopy(value, srcBegin, dst, dstBegin, srcEnd - srcBegin);
}

请注意,您得到的是 String index out of range: 90 所以一定是 srcEnd > count 返回 true。因此,附加的字符串现在比传递的 len 短。很明显肯定是被别的线程乱动了。