Por que o seguinte trabalho? Eu esperaria que uma NullPointerException
fosse lançada.
String s = null; s = s + "hello"; System.out.println(s); // prints "nullhello"
O JLS 5, Seção 15.18.1.1 JLS 8 § 15.18.1 “Operador de Concatenação de Cadeia +” , levando ao JLS 8, § 5.1.11 “Conversão de Cadeia” , requer que esta operação tenha sucesso sem falha:
… Agora apenas os valores de referência precisam ser considerados. Se a referência é nula, ela é convertida para a string “null” (quatro caracteres ASCII n, u, l, l). Caso contrário, a conversão é executada como se por uma invocação do método toString do object referenciado sem argumentos; mas se o resultado de chamar o método toString for nulo, a cadeia “null” será usada.
Vamos dar uma olhada no bytecode! O compilador pega seu código:
String s = null; s = s + "hello"; System.out.println(s); // prints "nullhello"
e compila em bytecode como se você tivesse escrito isso:
String s = null; s = new StringBuilder(String.valueOf(s)).append("hello").toString(); System.out.println(s); // prints "nullhello"
(Você pode fazer isso sozinho usando javap -c
)
Os methods de acréscimo de StringBuilder
todos manipulam null bem. Neste caso, porque null
é o primeiro argumento, String.valueOf()
é invocado, uma vez que StringBuilder não possui um construtor que toma qualquer tipo de referência arbitrária.
Se você tivesse feito s = "hello" + s
vez disso, o código equivalente seria:
s = new StringBuilder("hello").append(s).toString();
onde, neste caso, o método append recebe o valor nulo e, em seguida, o delega para String.valueOf()
.
Nota: A concatenação de strings é na verdade um dos raros lugares onde o compilador decide qual (is) otimização (s) executar. Como tal, o código “exato equivalente” pode diferir de compilador para compilador. Essa otimização é permitida pelo JLS, Seção 15.18.1.2 :
Para aumentar o desempenho da concatenação de cadeias repetidas, um compilador Java pode usar a class StringBuffer ou uma técnica semelhante para reduzir o número de objects String intermediários que são criados pela avaliação de uma expressão.
O compilador que eu usei para determinar o “código equivalente” acima foi o compilador do Eclipse, ecj .
Consulte a seção 5.4 e 15.18 da especificação da linguagem Java:
A conversão de string se aplica somente aos operandos do operador binário + quando um dos argumentos é uma String. Neste único caso especial, o outro argumento para o + é convertido em um String, e um novo String que é a concatenação das duas strings é o resultado do +. A conversão de string é especificada em detalhes na descrição do operador de concatenação de string +.
e
Se apenas uma expressão de operando for do tipo String, a conversão de sequência será executada no outro operando para produzir uma sequência em tempo de execução. O resultado é uma referência a um object String (recém-criado, a menos que a expressão seja uma expressão constante em tempo de compilation (§15.28)) que é a concatenação das duas cadeias de operandos. Os caracteres do operando esquerdo precedem os caracteres do operando direito na string recém-criada. Se um operando do tipo String for nulo, a cadeia “null” será usada em vez desse operando.
A segunda linha é transformada no seguinte código:
s = (new StringBuilder()).append((String)null).append("hello").toString();
Os methods append podem manipular argumentos null
.
Você não está usando o “null” e, portanto, você não recebe a exceção. Se você quiser o NullPointer, apenas faça
String s = null; s = s.toString() + "hello";
E acho que o que você quer fazer é:
String s = ""; s = s + "hello";
Esse é o comportamento especificado no método String.valueOf(Object)
da API Java. Quando você faz concatenação, valueOf
é usado para obter a representação de String
. Existe um caso especial se o Object for null
, caso em que a string "null"
é usada.
public static String valueOf(Object obj)
Retorna a representação de string do argumento Object.
parameters: obj – um object.
Retorna:
se o argumento for nulo, então uma string igual a “null”; caso contrário, o valor de obj.toString () será retornado.