Es war sehr verwirrend für mich, diese Situation zu beobachten:
Integer i = null;
String str = null;
if (i == null) { //Nothing happens
...
}
if (str == null) { //Nothing happens
}
if (i == 0) { //NullPointerException
...
}
if (str == "0") { //Nothing happens
...
}
Da ich denke, dass die Boxoperation zuerst ausgeführt wird (dh Java versucht, den int-Wert zu extrahieren null
) und die Vergleichsoperation eine niedrigere Priorität hat, wird die Ausnahme ausgelöst.
Die Frage ist: Warum ist es so in Java implementiert? Warum hat das Boxen eine höhere Priorität als das Vergleichen von Referenzen? Oder warum haben sie null
vor dem Boxen keine Überprüfung durchgeführt ?
Im Moment sieht es inkonsistent aus, wenn NullPointerException
es mit umschlossenen Grundelementen und nicht mit echten Objekttypen geworfen wird .
java
nullpointerexception
boxing
römisch
quelle
quelle
Antworten:
Die kurze Antwort
Der entscheidende Punkt ist folgender:
==
zwischen zwei Referenztypen ist immer ReferenzvergleichInteger
undString
, möchten Sieequals
stattdessen verwenden==
zwischen einem Referenztyp und einem numerischen Grundtyp ist immer ein numerischer Vergleichnull
wirft immerNullPointerException
String
, ist es in der Tat KEIN primitiver TypDie obigen Anweisungen gelten für jeden gültigen Java-Code. Mit diesem Verständnis gibt es keinerlei Inkonsistenz in dem von Ihnen präsentierten Snippet.
Die lange Antwort
Hier sind die relevanten JLS-Abschnitte:
Dies erklärt Folgendes:
Integer i = null; String str = null; if (i == null) { // Nothing happens } if (str == null) { // Nothing happens } if (str == "0") { // Nothing happens }
Beide Operanden sind Referenztypen, und deshalb
==
ist dies der Vergleich der Referenzgleichheit.Dies erklärt auch Folgendes:
System.out.println(new Integer(0) == new Integer(0)); // "false" System.out.println("X" == "x".toUpperCase()); // "false"
Um
==
numerische Gleichheit zu erreichen, muss mindestens einer der Operanden ein numerischer Typ sein :Dies erklärt:
Integer i = null; if (i == 0) { //NullPointerException }
Hier ist ein Auszug aus Effective Java 2nd Edition, Punkt 49: Ziehen Sie Grundelemente Boxed-Grundelementen vor :
Es gibt Orte, an denen Sie keine andere Wahl haben, als Box-Primitive zu verwenden, z. B. Generika. Andernfalls sollten Sie ernsthaft überlegen, ob eine Entscheidung zur Verwendung von Box-Primitiven gerechtfertigt ist.
Verweise
Integer
zu Typint
"r
istnull
, wirft Unboxing Umwandlung einesNullPointerException
“==
und!=
==
und!=
Verwandte Fragen
Integers
Tritt beim Vergleich von zwei in Java ein automatisches Unboxing auf?==
aber nichtequals()
?Verwandte Fragen
int num = Integer.getInteger("123")
wirftNullPointerException
? (!!!)String.equals
versus==
quelle
someRef == 0
ist immer ein numerischer Vergleich, es ist eine sehr gute Wahl, da der Vergleich der Referenzen von zwei Grundelementen in Kästchen fast immer ein Programmiererfehler ist. In diesem Fall wäre es sinnlos, standardmäßig auf Vergleiche zu verweisen.(myInteger == 0)
mit sich(myInteger != null && myInteger == 0)
stattdessen auf den Entwickler zu verlassen , diese vorformulierten null-checking Code zu schreiben? IMO Ich sollte in der Lage sein zu überprüfenif (myBoolean)
und das solltetrue
genau dann ausgewertet werden, wenn der zugrunde liegende Wert spezifisch isttrue
- ich sollte nicht zuerst null prüfen müssen.Ihr NPE-Beispiel entspricht diesem Code dank Autoboxing :
if ( i.intValue( ) == 0 )
Daher NPE wenn
i
istnull
.quelle
if (i == 0) { //NullPointerException ... }
Ich bin eine ganze Zahl und die 0 ist eine int. In dem, was wirklich getan wird, ist so etwas
i.intValue() == 0
Und dies verursacht den nullPointer, weil das i null ist. Für String haben wir diese Operation nicht, deshalb gibt es dort keine Ausnahme.
quelle
Die Hersteller von Java hätten den
==
Operator so definieren können, dass er direkt auf Operanden unterschiedlicher Typen einwirkt. In diesem Fall könnteInteger I; int i;
der VergleichI==i;
die Frage stellen: "EnthältI
ein Verweis auf einenInteger
Wert, dessen Wert isti
?" - eine Frage, die ohne Schwierigkeiten beantwortet werden kann auch wennI
null ist. Leider prüft Java nicht direkt, ob Operanden unterschiedlicher Typen gleich sind. Stattdessen wird geprüft, ob die Sprache die Konvertierung des Typs eines Operanden in den Typ des anderen zulässt, und - falls dies der Fall ist - der konvertierte Operand mit dem nicht konvertierten verglichen. Ein solches Verhalten bedeutet , dass für Variablenx
,y
undz
mit einigen Kombinationen von Arten, ist es möglich zu habenx==y
undy==z
aberx!=z
[zB x = 16777216f y = 16777216 z = 16777217]. Dies bedeutet auch, dass der VergleichI==i
übersetzt wird als "I in ein konvertierenint
und, wenn dies keine Ausnahme auslöst, miti
" vergleichen ".quelle
==
in der Weise , dass in allen Fällen , wenn , wox==y
,y==z
undx==z
alle Kompilierung ohne Beschwerde, die drei Vergleiche als Äquivalenzrelation verhält. Neugierig, dass Designer alle möglichen ausgefallenen Sprachfunktionen nutzen, aber die axiomatische Konformität ignorieren.Es ist wegen Javas Autoboxing- Funktion. Der Compiler erkennt, dass Sie auf der rechten Seite des Vergleichs eine primitive Ganzzahl verwenden und den Wrapper-Integer-Wert ebenfalls in einen primitiven int-Wert entpacken müssen.
Da dies nicht möglich ist (es ist null, wie Sie dargelegt haben),
NullPointerException
wird das geworfen.quelle
In
i == 0
Java wird versucht, das automatische Entpacken durchzuführen und einen numerischen Vergleich durchzuführen (dh "Wird der im Wrapper-Objekt gespeicherte Wert durchi
denselben Wert wie der Wert0
?").Da
i
wirdnull
das Unboxing ein werfenNullPointerException
.Die Argumentation lautet wie folgt:
Der erste Satz von JLS § 15.21.1 Numerische Gleichheitsoperatoren == und! = Lautet wie folgt :
Es
i
ist klar, dass es in einen numerischen Typ konvertierbar ist und0
ein numerischer Typ ist, sodass die binäre numerische Heraufstufung für die Operanden durchgeführt wird.§ 5.6.2 Binäre numerische Werbung sagt (unter anderem):
§ 5.1.8 Unboxing Conversion sagt (unter anderem):
quelle
Schreiben Sie einfach eine Methode und rufen Sie sie auf, um NullPointerException zu vermeiden.
public static Integer getNotNullIntValue(Integer value) { if(value!=null) { return value; } return 0; }
quelle