web-dev-qa-db-fra.com

Concaténation de chaînes nulles dans Java

Pourquoi fonctionne ce qui suit? Je m'attendrais à un NullPointerException à lancer.

String s = null;
s = s + "hello";
System.out.println(s); // prints "nullhello"
153
yavoh

Pourquoi must ça marche?

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.

Comment ça marche?

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 .

177
Mark Peters

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.

24
Jonathon Faust

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.

11
Roland Illig

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";
10
krico

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.

7
wkl