Pourquoi fonctionne ce qui suit? Je m'attendrais à un NullPointerException
à lancer.
String s = null;
s = s + "hello";
System.out.println(s); // prints "nullhello"
Le JLS 5, section 15.18.1.1JLS 8 § 15.18.1 "Opérateur de concaténation de chaînes +" , conduisant à JLS 8, § 5.1.11 "Conversion de chaînes" , nécessite que cette opération aboutisse sans échec:
... Seules les valeurs de référence doivent être prises en compte. Si la référence est null, elle est convertie en chaîne "null" (quatre ASCII caractères n, u, Sinon, la conversion est effectuée comme si la méthode toString de l'objet référencé était invoquée sans argument, mais si le résultat de l'appel de la méthode toString est null, la chaîne "null" est utilisée à la place.
Regardons le bytecode! Le compilateur prend votre code:
String s = null;
s = s + "hello";
System.out.println(s); // prints "nullhello"
et le compile en bytecode comme si vous aviez écrit ceci:
String s = null;
s = new StringBuilder(String.valueOf(s)).append("hello").toString();
System.out.println(s); // prints "nullhello"
(Vous pouvez le faire vous-même en utilisant javap -c
)
Les méthodes append de StringBuilder
all traitent nullement parfaitement. Dans ce cas, étant donné que null
est le premier argument, String.valueOf()
est appelé à la place, car StringBuilder n'a pas de constructeur qui utilise un type de référence arbitraire.
Si vous deviez utiliser s = "hello" + s
À la place, le code équivalent serait:
s = new StringBuilder("hello").append(s).toString();
où dans ce cas la méthode append prend la valeur null et alors le délègue à String.valueOf()
.
Remarque: La concaténation de chaînes est en fait l'un des rares endroits où le compilateur doit décider du ou des optimisations à effectuer. En tant que tel, le code "équivalent exact" peut différer d'un compilateur à l'autre. Cette optimisation est autorisée par JLS, Section 15.18.1.2 :
Pour augmenter les performances de la concaténation de chaînes répétée, un compilateur Java peut utiliser la classe StringBuffer ou une technique similaire afin de réduire le nombre d'objets String intermédiaires créés lors de l'évaluation d'une expression.
Le compilateur que j'ai utilisé pour déterminer le "code équivalent" ci-dessus était le compilateur d'Eclipse, ecj .
Voir les sections 5.4 et 15.18 de la Java Spécification de la langue:
La conversion de chaîne ne s'applique qu'aux opérandes de l'opérateur binaire + lorsque l'un des arguments est une chaîne. Dans ce cas particulier unique, l'autre argument du + est converti en une chaîne et une nouvelle chaîne, qui est la concaténation des deux chaînes, est le résultat du +. La conversion de chaîne est spécifiée en détail dans la description de l'opérateur de concaténation de chaîne +.
et
Si une seule expression d'opérande est de type String, la conversion de chaîne est effectuée sur l'autre opérande afin de générer une chaîne au moment de l'exécution. Le résultat est une référence à un objet String (nouvellement créé, à moins que l'expression ne soit une expression constante à la compilation (§15.28)), qui est la concaténation des deux chaînes d'opérandes. Les caractères de l'opérande de gauche précèdent ceux de l'opérande de droite dans la chaîne nouvellement créée. Si un opérande de type String est null, la chaîne "null" est utilisée à la place de cet opérande.
La deuxième ligne est transformée en code suivant:
s = (new StringBuilder()).append((String)null).append("hello").toString();
Les méthodes append peuvent gérer les arguments null
.
Vous n'utilisez pas le "null" et par conséquent, vous n'obtenez pas l'exception. Si vous voulez le NullPointer, faites juste
String s = null;
s = s.toString() + "hello";
Et je pense que ce que vous voulez faire est:
String s = "";
s = s + "hello";
Ce comportement est spécifié dans la méthode String.valueOf(Object)
de l'API Java. Lorsque vous effectuez une concaténation, valueOf
est utilisé pour obtenir le Représentation String
Il existe un cas particulier si l'objet est null
, auquel cas la chaîne "null"
est utilisée.
public static String valueOf(Object obj)
Retourne la représentation sous forme de chaîne de l'argument Object.
Paramètres: obj - un objet.
Résultats:
si l'argument est null, alors une chaîne égale à "null"; sinon, la valeur de obj.toString () est renvoyée.