StringBuilder生产使用的一次事故

2023-04-04 10:10:07 浏览数 (3)

StringBuilder生产使用的一次事故

使用Java实现较长逻辑的代码中,无可避免会创建众多的String对象,又是为了节省内存空间以及优化程序效率,会选择使用StringBuilder或者StringBuffer来代替String对象。

起因

项目部署后,NPE的次数变多了,且均在StringBuilder构造器中,这引起的项目维护人的重视!

验证

代码语言:javascript复制
public class StringBuilderTest {
    
    public static void main(String[] args) {
        StringBuilder builder = new StringBuilder(null);
    }
}

执行结果如下:

到了这一步,基本算是复现了线上问题,确实是编码问题?那么为什么这样呢,明明append可以放入空指针对象呀? 深入源码查看,进入StringBuilder.java的带参构造器

代码语言:javascript复制
    /**
     * 构造初始化为指定字符串内容的字符串生成器。字符串生成器的初始容量为 16 加上字符串参数的长度。
     * 参数:str – 缓冲区的初始内容。
     */
    public StringBuilder(String str) {
        super(str.length()   16);
        append(str);
    }

到这里算是明白了,调用length()方法,所以会有空指针的异常,瞬间感觉这个错误很低级。

解决方案

基于以上问题,基本解决方案就是,避免传入NULL对象,或者使用append()

方法一:

对于使用StringBuilder构造器的对象,进行非空判断,例如:

代码语言:javascript复制
public static void main(String[] args) {
    String obj = null;
    if (obj != null) {
        StringBuilder builder = new StringBuilder(obj);
    }
}
方法二:
代码语言:javascript复制
public static void main(String[] args) {
    String obj = null;
    StringBuilder builder = new StringBuilder();
    builder.append(obj);
}

由于append在添加字符串时,会先进行判空并 替代塞入"null",所以这个方法不提倡。 那么它的源码是如何实现的呢? StringBuilder.java

代码语言:javascript复制
@Override
public StringBuilder append(String str) {
     super.append(str);
     return this;
 }

AbstractStringBuilder.java

代码语言:javascript复制
/**
 * 将指定的字符串追加到此字符序列。将按顺序追加 String 参数的字符,使此序列的长度按参数的长度增加。
 * 如  果 str 为 null,则附加四个字符 “null”。设 n 是执行追加方法之前此字符序列的长度。则新字符序
 * 列中索引 k 处的字符等于旧字符序列中索引 k 处的字符,如果 k 小于 n;否则,它等于参数 str 中索引
 *  k-n 处的字符。
 * 参数:str – 一个字符串。
 * 返回:对此对象的引用。
 **/
public AbstractStringBuilder append(String str) {
    if (str == null)
        return appendNull();
    int len = str.length();
    ensureCapacityInternal(count   len);
    str.getChars(0, len, value, count);
    count  = len;
    return this;
}

private AbstractStringBuilder appendNull() {
    int c = count;
    ensureCapacityInternal(c   4);
    final char[] value = this.value;
    value[c  ] = 'n';
    value[c  ] = 'u';
    value[c  ] = 'l';
    value[c  ] = 'l';
    count = c;
    return this;
}

以上就是一次事故给自己的一些思考,优化可以,但是不可以多写bug。

0 人点赞