Почему в моем байт-коде конкатенации строк есть вызов "String.valueOf(Object)"?

У меня есть два следующих метода в небольшом приложении микробенчмарка (под управлением JDK 1.6):

public static String testStringBuilder3(String str1, String str2, String str3, String str4, String str5) {
    return new StringBuilder(str1).append("-").append(str2).append("-").append(str3).append("-").append(str4).append("-").append(str5).toString();
}

public static String testStringBuilder4(String str1, String str2, String str3, String str4, String str5) {
    return str1 + "-" + str2 + "-" + str3 + "-" + str4 + "-" + str5;
}

Я ожидаю, что байт-код для этих двух методов будет идентичным. Они почти идентичны, с одним небольшим отличием, которое я хотел бы понять.

Вот байт-код для первого метода (я не могу заставить Stackru правильно его отформатировать):

public static java.lang.String testStringBuilder3(java.lang.String, java.lang.String, java.lang.String, java.lang.String, java.lang.String);
Code:
  0:    new #164; //class java/lang/StringBuilder
  3:    dup
  4:    aload_0
  5:    invokespecial   #170; //Method java/lang/StringBuilder."<init>":(Ljava/lang/String;)V
  8:    ldc #182; //String -
 10:    invokevirtual   #172; //Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
 13:    aload_1
 14:    invokevirtual   #172; //Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
 17:    ldc #182; //String -
 19:    invokevirtual   #172; //Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
 22:    aload_2
 23:    invokevirtual   #172; //Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
 26:    ldc #182; //String -
 28:    invokevirtual   #172; //Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
 31:    aload_3
 32:    invokevirtual   #172; //Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
 35:    ldc #182; //String -
 37:    invokevirtual   #172; //Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
 40:    aload   4
 42:    invokevirtual   #172; //Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
 45:    invokevirtual   #176; //Method java/lang/StringBuilder.toString:()Ljava/lang/String;
 48:    areturn

И вот байт-код для второго метода:

public static java.lang.String testStringBuilder4(java.lang.String, java.lang.String, java.lang.String, java.lang.String, java.lang.String);
Code:
  0:    new #164; //class java/lang/StringBuilder
  3:    dup
  4:    aload_0
  5:    invokestatic    #166; //Method java/lang/String.valueOf:(Ljava/lang/Object;)Ljava/lang/String;
  8:    invokespecial   #170; //Method java/lang/StringBuilder."<init>":(Ljava/lang/String;)V
  11:   ldc #182; //String -
  13:   invokevirtual   #172; //Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
  16:   aload_1
  17:   invokevirtual   #172; //Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
  20:   ldc #182; //String -
  22:   invokevirtual   #172; //Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
  25:   aload_2
  26:   invokevirtual   #172; //Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
  29:   ldc #182; //String -
  31:   invokevirtual   #172; //Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
  34:   aload_3
  35:   invokevirtual   #172; //Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
  38:   ldc #182; //String -
  40:   invokevirtual   #172; //Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
  43:   aload   4
  45:   invokevirtual   #172; //Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
  48:   invokevirtual   #176; //Method java/lang/StringBuilder.toString:()Ljava/lang/String;
  51:   areturn

Единственная разница между ними заключается в следующей строке байт-кода для второго метода:

   5:   invokestatic    #166; //Method java/lang/String.valueOf:(Ljava/lang/Object;)Ljava/lang/String;

Что это может делать?

1 ответ

Решение

Из источника JDK:

public static String valueOf(Object obj) {
    return (obj == null) ? "null" : obj.toString();
}

Он проверяет, что первая переменная не равна нулю, иначе она выдаст NullPointerException, так как это ожидаемое поведение StringBuilder(String str)

Пример:

public class StringTest
{
  public static void main(String a[])
  {
    System.out.println(testStringBuilder3(null, null, null, null, null));
    System.out.println(testStringBuilder4(null, null, null, null, null));
  }
 public static String testStringBuilder3(String str1, String str2, String str3, String str4, String str5) {
    return str1 + "-" + str2 + "-" + str3 + "-" + str4 + "-" + str5;
  }
  public static String testStringBuilder4(String str1, String str2, String str3, String str4, String str5) {
    return new StringBuilder(str1).append("-").append(str2).append("-").append(str3).append("-").append(str4).append("-").append(str5).toString();
  }
}

Выход:

null-null-null-null-null
Exception in thread "main" java.lang.NullPointerException
    at java.lang.StringBuilder.<init>(Unknown Source)
    at StringTest.testStringBuilder3(StringTest.java:15)
    at StringTest.main(StringTest.java:11)
Другие вопросы по тегам