Ответ 1
Зачем это нужно?
JLS 5, раздел 15.18.1.1 JLS 8 § 15.18.1 "Оператор конкатенации строк +" , приводящий к JLS 8, § 5.1.11 "Преобразование строк" , эта операция должна выполняться без сбоев:
... Теперь нужно учитывать только опорные значения. Если ссылка равна null, она преобразуется в строку "null" (четыре символа ASCII n, u, l, l). В противном случае преобразование выполняется как бы путем вызова метода toString ссылочного объекта без аргументов; но если результат вызова метода toString равен нулю, вместо этого используется строка "null".
Как это работает?
Посмотрите на байт-код! Компилятор принимает ваш код:
String s = null;
s = s + "hello";
System.out.println(s); // prints "nullhello"
и скомпилирует его в байт-код, как если бы вы написали это:
String s = null;
s = new StringBuilder(String.valueOf(s)).append("hello").toString();
System.out.println(s); // prints "nullhello"
(Вы можете сделать это самостоятельно, используя javap -c
)
Применить методы StringBuilder
все дескриптор null просто отлично. В этом случае, поскольку null
- это первый аргумент, вместо него вызывается String.valueOf()
, поскольку StringBuilder не имеет конструктора, который принимает произвольный ссылочный тип.
Если бы вы сделали s = "hello" + s
вместо этого, эквивалентный код:
s = new StringBuilder("hello").append(s).toString();
где в этом случае метод append принимает значение null, а затем передает его на String.valueOf()
.
Примечание. Конкатенация строк на самом деле является одним из редких мест, где компилятор принимает решение о том, какую оптимизацию выполнить. Таким образом, "точный эквивалентный" код может отличаться от компилятора к компилятору. Эта оптимизация разрешена JLS, раздел 15.18.1.2:
Чтобы увеличить производительность повторной конкатенации строк, компилятор Java может использовать класс StringBuffer или подобный метод для уменьшения количества промежуточных объектов String, созданных при оценке выражения.
Компилятором, который я использовал для определения "эквивалентного кода" выше, был компилятор Eclipse, ecj.