Aucune exception lors de la conversion de type avec un null en java

227
String x = (String) null;

Pourquoi il n'y a aucune exception dans cette déclaration?

String x = null;
System.out.println(x);

Il imprime null. Mais la .toString()méthode doit lever une exception de pointeur nul.

Vicky
la source
de quelle exception parlez-vous, compilateur?
Sajan Chandran

Réponses:

323

Vous pouvez effectuer un cast nullvers n'importe quel type de référence sans aucune exception.

La printlnméthode ne lance pas de pointeur nul car elle vérifie d'abord si l'objet est nul ou non. S'il est nul, il imprime simplement la chaîne "null". Sinon, il appellera la toStringméthode de cet objet.

Ajout de plus de détails: méthode d'appel interne des méthodes d'impression String.valueOf(object)sur l'objet d'entrée. Et dans la valueOfméthode, cette vérification permet d'éviter une exception de pointeur nul:

return (obj == null) ? "null" : obj.toString();

Pour le reste de votre confusion, appeler n'importe quelle méthode sur un objet nul devrait lever une exception de pointeur nul, sinon un cas spécial.

Juned Ahsan
la source
1
@JunedAhsan quels cas particuliers l'empêcheraient de lancer un NPE?
Holloway
@Trengot Cochez une mention dans la réponse de Peter ci-dessous.
Juned Ahsan
144

Vous pouvez effectuer un cast nullvers n'importe quel type de référence. Vous pouvez également appeler des méthodes qui gèrent un nullcomme argument, par exemple System.out.println(Object), mais vous ne pouvez pas référencer une nullvaleur et appeler une méthode dessus.

BTW Il existe une situation délicate où il semble que vous pouvez appeler des méthodes statiques sur des nullvaleurs.

Thread t = null;
t.yield(); // Calls static method Thread.yield() so this runs fine.
Peter Lawrey
la source
12
Sensationnel. Si on me le demandait, je serais sûr à 100% que cela lèverait une exception. Un cas délicat en effet.
Magnilex
2
@Magnilex: Absolument! il s'agit d'une question d'astuce d'examen OCPJP typique.
ccpizza
3
N'est-ce pas parce que le compilateur en bytecode "l'optimise" t.yield() -> Thread.yeld() quand même? Similaire à la façon dont final int i = 1; while (i == 1)est optimisé pourwhile(true)
SGal
@SGal C'est encore mieux car la deuxième optimisation n'est pas obligatoire AFAIK tandis que la première l'est un peu.
Paul Stelian
36

C'est par conception. Vous pouvez effectuer un cast nullvers n'importe quel type de référence. Sinon, vous ne pourrez pas l'affecter à des variables de référence.

André Stannek
la source
Merci! cette note concernant l'attribution de null aux variables de référence est vraiment utile!
Max
22

La conversion de valeurs null est requise pour la construction suivante où une méthode est surchargée et si null est transmis à ces méthodes surchargées, le compilateur ne sait pas comment lever l'ambiguïté, nous devons donc transtyper null dans ces cas:

class A {
  public void foo(Long l) {
    // do something with l
  }
  public void foo(String s) {
    // do something with s      
  }
}
new A().foo((String)null);
new A().foo((Long)null);

Sinon, vous ne pourriez pas appeler la méthode dont vous avez besoin.

Mewel
la source
Dans la plupart des cas, la conversion est implicite, par exemple, String bar = null;convertit la nullvaleur en String. Jusqu'à présent, je n'avais qu'à transtyper explicitement null dans un test où une méthode était surchargée et je voulais tester son comportement avec une entrée null. Pourtant, bon à savoir, j'étais sur le point d'écrire une réponse similaire avant de trouver la vôtre.
Vlasec
Fait amusant: l instanceof Longet s instanceof Stringreviendra falsedans ces cas.
Attila Tanyi
7

Println(Object) les usages String.valueOf()

public static String valueOf(Object obj) {
    return (obj == null) ? "null" : obj.toString();
}

Print(String) vérifie null.

public void print(String s) {
    if (s == null) {
        s = "null";
    }
    write(s);
}
rocketboy
la source
5

De nombreuses réponses mentionnent déjà ici

Vous pouvez transtyper null en n'importe quel type de référence

et

Si l'argument est nul, alors une chaîne égale à "null"

Je me suis demandé où cela est spécifié et j'ai cherché la spécification Java:

La référence nulle peut toujours être affectée ou convertie en n'importe quel type de référence (§5.2, §5.3, §5.5).

Si la référence est nulle, elle est convertie en la chaîne "null" (quatre caractères ASCII n, u, l, l).

Arigion
la source
3

Comme d'autres l'ont écrit, vous pouvez annuler tout. Normalement, vous n'en auriez pas besoin, vous pouvez écrire:

String nullString = null;

sans y mettre le casting.

Mais il y a des occasions où de tels lancements ont du sens:

a) si vous voulez vous assurer qu'une méthode spécifique est appelée, comme:

void foo(String bar) {  ... }
void foo(Object bar) {  ... }

alors cela ferait une différence si vous tapez

foo((String) null) vs. foo(null)

b) si vous avez l'intention d'utiliser votre IDE pour générer du code; par exemple, j'écris généralement des tests unitaires comme:

@Test(expected=NullPointerException.class)
public testCtorWithNullWhatever() {
    new MyClassUnderTest((Whatever) null);
}

Je fais du TDD; cela signifie que la classe "MyClassUnderTest" n'existe probablement pas encore. En écrivant ce code, je peux ensuite utiliser mon IDE pour générer d'abord la nouvelle classe; et pour générer ensuite un constructeur acceptant un argument "W Any" "prêt à l'emploi" - l'EDI peut comprendre à partir de mon test que le constructeur doit prendre exactement un argument de type Wthing.

GhostCat
la source
2

Imprimer :

Imprimez un objet. La chaîne produite par la méthode String.valueOf (Object) est traduite en octets

ValueOf :

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

Il retournera simplement une chaîne avec la valeur "null" lorsque l'objet l'est null.

Jeroen Vannevel
la source
2

C'est très pratique lorsque vous utilisez une méthode qui serait autrement ambiguë. Par exemple: JDialog a des constructeurs avec les signatures suivantes:

JDialog(Frame, String, boolean, GraphicsConfiguration)
JDialog(Dialog, String, boolean, GraphicsConfiguration)

J'ai besoin d'utiliser ce constructeur, car je veux définir la GraphicsConfiguration, mais je n'ai pas de parent pour cette boîte de dialogue, donc le premier argument doit être nul. En utilisant

JDialog(null, String, boolean, Graphicsconfiguration) 

est ambigu, donc dans ce cas, je peux restreindre l'appel en castant null à l'un des types pris en charge:

JDialog((Frame) null, String, boolean, GraphicsConfiguration)
Marten Jacobs
la source
0

Cette fonction de langue est pratique dans cette situation.

public String getName() {
  return (String) memberHashMap.get("Name");
}

Si memberHashMap.get ("Name") renvoie null, vous souhaitez toujours que la méthode ci-dessus renvoie null sans lever d'exception. Quelle que soit la classe, null est null.

Changgull Song
la source