Pourquoi String.valueOf (null) lève-t-il une NullPointerException?

127

selon la documentation, la méthode String.valueOf(Object obj)retourne:

si l'argument est null, alors une chaîne égale à "null"; sinon, la valeur de obj.toString()est renvoyée.

Mais comment se fait-il que j'essaye de faire ceci:

System.out.println("String.valueOf(null) = " + String.valueOf(null));

il jette NPE à la place? (essayez-le vous-même si vous ne croyez pas!)

    Exception dans le thread "main" java.lang.NullPointerException
    à java.lang.String. (Source inconnue)
    à java.lang.String.valueOf (source inconnue)

Comment cela se fait-il? La documentation me ment-elle? Est-ce un bug majeur en Java?

user282886
la source

Réponses:

201

Le problème est que la String.valueOfméthode est surchargée :

Le langage de spécification Java exige que dans ce type de cas, la surcharge la plus spécifique soit choisie:

JLS 15.12.2.5 Choix de la méthode la plus spécifique

Si plusieurs méthodes membres sont à la fois accessibles et applicables à un appel de méthode, il est nécessaire d'en choisir une pour fournir le descripteur de la répartition de la méthode d'exécution. Le langage de programmation Java utilise la règle selon laquelle la méthode la plus spécifique est choisie.

Un char[] est-un Object , mais tout Object n'est pas unchar[] . Par conséquent, char[]est plus spécifique que Object, et comme spécifié par le langage Java, la String.valueOf(char[])surcharge est choisie dans ce cas.

String.valueOf(char[])s'attend à ce que le tableau soit non- null, et comme nullest donné dans ce cas, il lance alors NullPointerException.

Le "correctif" simple consiste à convertir le nullexplicitement en Objectcomme suit:

System.out.println(String.valueOf((Object) null));
// prints "null"

Questions connexes


Morale de l'histoire

Il y en a plusieurs importants:

  • Efficace Java 2nd Edition, Item 41: Utilisez la surcharge judicieusement
    • Ce n'est pas parce que vous pouvez surcharger que vous devriez à chaque fois
    • Ils peuvent prêter à confusion (surtout si les méthodes font des choses très différentes)
  • En utilisant un bon IDE, vous pouvez vérifier quelle surcharge est sélectionnée au moment de la compilation
    • Avec Eclipse, vous pouvez passer la souris sur l'expression ci-dessus et voir qu'en effet , la valueOf(char[])surcharge est sélectionnée!
  • Parfois, vous souhaitez lancer explicitement null(exemples à suivre)

Voir également


Au casting null

Il existe au moins deux situations dans lesquelles un cast explicite nullvers un type de référence spécifique est nécessaire:

  • Pour sélectionner la surcharge (comme indiqué dans l'exemple ci-dessus)
  • Pour donner nullcomme argument unique à un paramètre vararg

Un exemple simple de ce dernier est le suivant:

static void vararg(Object... os) {
    System.out.println(os.length);
}

Ensuite, nous pouvons avoir les éléments suivants:

vararg(null, null, null); // prints "3"
vararg(null, null);       // prints "2"
vararg(null);             // throws NullPointerException!

vararg((Object) null);    // prints "1"

Voir également

Questions connexes

lubrifiants polygènes
la source
5
Une autre suggestion: lorsque vous surchargez une méthode et qu'un argument peut être appelé sur deux surcharges (comme nulldans ce cas), assurez-vous que les deux surcharges agissent de la même manière par rapport à cette valeur!
Joachim Sauer
3
@Joachim: Je viens de lire l'article, et j'ai été agréablement surpris de constater que ces deux méthodes étaient explicitement discutées! Bloch est allé plus loin et prétend que depuis String.valueOf(Object)et valueOf(char[])faire des choses complètement différentes de toute façon (indépendamment nullou non) que peut-être qu'ils n'auraient pas dû être des surcharges en premier lieu.
polygenelubricants
Vous avez une question ... si vous avez une méthode qui renvoie un objet, l'instruction return null;serait exactement la même chose que return (Object) null;?
user972276
17

Le problème est que vous appelez String.valueOf(char[])et non String.valueOf(Object) .

La raison en est que Java choisira toujours la version la plus spécifique d'une méthode surchargée qui fonctionne avec les paramètres fournis. nullest une valeur valide pour un Objectparamètre, mais c'est aussi une valeur valide pour un char[]paramètre.

Pour que Java utilise la Objectversion, passez nullvia une variable ou spécifiez un cast explicite en Object:

Object o = null;
System.out.println("String.valueOf(null) = " + String.valueOf(o));
// or
System.out.println("String.valueOf(null) = " + String.valueOf((Object) null));
Joachim Sauer
la source
5

Un bogue, numéroté 4867608 a été déposé pour ce chemin en 2003, qui a été résolu comme "ne résoudra pas" avec cette explication.

Nous ne pouvons pas changer cela en raison de contraintes de compatibilité. Notez que c'est la méthode publique statique String valueOf (char data []) qui finit par être appelée et qu'elle ne mentionne pas le remplacement de "null" pour les arguments nuls.

@ ###. ### 2003-05-23

cbare
la source
0

Utilisation String.valueOf(null: Any)dans Scala.

Profiterole
la source