Warum unterstützt die String switch-Anweisung keinen Nullfall?
Lesezeit: 7 Minuten
Prashant Bhate
Ich frage mich nur, warum das Java 7 switch Aussage unterstützt nicht a null Fall und wirft stattdessen NullPointerException? Siehe die kommentierte Zeile unten (Beispiel aus den Java-Tutorials-Artikel auf switch):
Dies hätte eine vermieden if Bedingung für Nullprüfung vor jedem switch verwenden.
Keine schlüssige Antwort darauf, da wir nicht die Leute sind, die die Sprache gemacht haben. Alle Antworten werden reine Vermutungen sein.
– Sternchen
15. August 2013 um 23:22 Uhr
Ein Versuch, einzuschalten null wird eine Ausnahme verursachen. Führen Sie ein if prüfen Auf nulldann gehen Sie in die switch Aussage.
– gparjani
15. August 2013 um 23:22 Uhr
Von dem JLS: Nach Einschätzung der Entwickler der Programmiersprache Java [throwing a NullPointerException if the expression evaluates to null at runtime] ist ein besseres Ergebnis, als die gesamte switch-Anweisung stillschweigend zu überspringen oder die Anweisungen (falls vorhanden) nach dem Standardlabel (falls vorhanden) auszuführen.
– gparjani
15. August 2013 um 23:37 Uhr
@gparyani: Mach das zu einer Antwort. Das klingt sehr offiziell und endgültig.
– Thilo
15. August 2013 um 23:42 Uhr
@JeffGohlke: “Es gibt keine Möglichkeit, eine Warum-Frage zu beantworten, es sei denn, Sie sind die Person, die die Entscheidung getroffen hat.”… nun, gparyanis Kommentar beweist das Gegenteil
– Benutzer541686
15. August 2013 um 23:51 Uhr
Paul Bellora
Wie damryfbfnetsi in den Kommentaren betont, JLS §14.11 hat folgenden Hinweis:
Das Nutzungsverbot null als Switch-Label verhindert, dass Code geschrieben wird, der niemals ausgeführt werden kann. Wenn die switch Der Ausdruck ist vom Referenztyp, d. h. String oder ein eingerahmter primitiver Typ oder ein Aufzählungstyp, dann tritt ein Laufzeitfehler auf, wenn der Ausdruck zu ausgewertet wird null zur Laufzeit. Nach Ansicht der Entwickler der Programmiersprache Java ist dies ein besseres Ergebnis, als das Ganze stillschweigend zu überspringen switch Anweisung oder die Entscheidung, die Anweisungen (falls vorhanden) nach der auszuführen default Etikett (falls vorhanden).
(Hervorhebung von mir)
Während der letzte Satz die Möglichkeit der Verwendung überspringt case null:scheint vernünftig und bietet einen Einblick in die Absichten der Sprachdesigner.
Betrachten wir eher Implementierungsdetails, diesen Blogbeitrag von Christian Hujer hat einige aufschlussreiche Spekulationen darüber, warum null ist in Schaltern nicht erlaubt (obwohl es sich um die enum Schalter statt der String Schalter):
Unter der Haube die switch -Anweisung wird normalerweise in einen Tablesswitch-Bytecode kompiliert. Und das “physikalische” Argument dazu switch sowie seine Fälle sind ints. Der einzuschaltende Int-Wert wird durch Aufrufen der Methode ermittelt Enum.ordinal(). Das […] Ordnungszahlen beginnen bei Null.
Das bedeutet Kartierung null zu 0 wäre keine gute idee. Ein Schalter am ersten Enum-Wert wäre nicht von Null zu unterscheiden. Vielleicht wäre es eine gute Idee gewesen, die Ordnungszahlen für Aufzählungen bei 1 zu zählen. Dies ist jedoch nicht so definiert, und diese Definition kann nicht geändert werden.
Während String Schalter sind unterschiedlich implementiert, die enum Schalter kam zuerst und hat den Präzedenzfall dafür geschaffen, wie sich das Einschalten eines Referenztyps verhalten sollte, wenn die Referenz ist null.
Es wäre eine große Verbesserung gewesen, die Nullbehandlung als Teil von a zuzulassen case null: wenn es exklusiv für implementiert worden wäre String. Aktuell alle String Die Prüfung erfordert sowieso eine Nullprüfung, wenn wir es richtig machen wollen, wenn auch meistens implizit, indem die String-Konstante wie in vorangestellt wird "123test".equals(value). Jetzt sind wir gezwungen, unsere switch-Anweisung wie in zu schreiben if (value != null) switch (value) {...
– JoJo
4. Februar 2016 um 23:06 Uhr
Zu “Null auf 0 abbilden wäre keine gute Idee”: Das ist eine Untertreibung, da der Wert von “.hashcode() 0 ist! Dies würde bedeuten, dass ein Null-String und ein String der Länge Null in einer switch-Anweisung identisch behandelt werden müssten, was eindeutig nicht realisierbar ist.
– Skomisa
16. Dezember 2017 um 2:41 Uhr
Was hat sie im Fall von enum daran gehindert, null auf -1 abzubilden?
– knackig
18. September 2019 um 2:54 Uhr
Im Algemeinen null ist unangenehm zu handhaben; vielleicht kann eine bessere Sprache ohne leben null.
Keine gute Idee, wenn month ist ein leerer String: Dadurch wird er genauso behandelt wie ein Null-String.
– gparjani
16. August 2013 um 21:11 Uhr
In vielen Fällen kann es durchaus sinnvoll sein, null als leeren String zu behandeln
– Eric Waldmeister
6. April 2014 um 21:41 Uhr
knackig
Es ist nicht schön, aber String.valueOf() ermöglicht es Ihnen, einen Null-String in einem Schalter zu verwenden. Wenn es findet nulles wandelt es um "null", andernfalls gibt es nur denselben String zurück, den Sie ihm übergeben haben. Wenn Sie nicht behandeln "null" explizit, dann wird es gehen default. Die einzige Einschränkung ist, dass es keine Möglichkeit gibt, zwischen dem String zu unterscheiden "null" und eine tatsächliche null Variable.
String month = null;
switch (String.valueOf(month)) {
case "january":
monthNumber = 1;
break;
case "february":
monthNumber = 2;
break;
case "march":
monthNumber = 3;
break;
case "null":
monthNumber = -1;
break;
default:
monthNumber = 0;
break;
}
return monthNumber;
Ich glaube, so etwas in Java zu tun, ist ein Antimuster.
– Lukasz Rzeszotarski
30. März 2018 um 5:59 Uhr
@ŁukaszRzeszotarski Das ist ziemlich genau das, was ich mit “es ist nicht schön” gemeint habe
– knackig
6. April 2018 um 14:05 Uhr
Prashant Bhate
Dies ist ein Versuch zu beantworten, warum es wirft NullPointerException
Die Ausgabe des Javap-Befehls unten zeigt dies case wird basierend auf dem Hashcode der ausgewählt switch Argumentzeichenfolge und wirft daher NPE, wenn .hashCode() wird auf Null-String aufgerufen.
Das bedeutet, basierend auf Antworten auf Kann Javas hashCode denselben Wert für verschiedene Zeichenfolgen erzeugen?, obwohl selten, besteht immer noch die Möglichkeit, dass zwei Fälle übereinstimmen (zwei Zeichenfolgen mit demselben Hash-Code). Siehe dieses Beispiel unten
int monthNumber;
String month = args[0];
switch (month) {
case "Ea":
monthNumber = 1;
break;
case "FB":
monthNumber = 2;
break;
// case null:
default:
monthNumber = 0;
break;
}
System.out.println(monthNumber);
Wie Sie sehen, wird nur ein Fall generiert "Ea" und "FB" aber mit zwei if Bedingungen, um auf eine Übereinstimmung mit jeder Groß-/Kleinschreibung zu prüfen. Sehr interessante und komplizierte Art, diese Funktionalität zu implementieren!
stätig
Lange Rede kurzer Sinn … (und hoffentlich interessant genug!!!)
Enum wurden zuerst in eingeführt Java1.5 (September 2004) und die Insekt auffordern zu Einschalten des Strings zulassen wurde vor langer Zeit abgelegt (Okt’95). Wenn Sie sich den Kommentar ansehen, der zu diesem Fehler gepostet wurde Juni 2004es sagt Don't hold your breath. Nothing resembling this is in our plans. Sieht so aus, als hätten sie aufgeschoben (ignoriert) diesen Fehler und starteten schließlich Java 1.5 im selben Jahr, in dem sie ‘enum’ mit einer Ordnungszahl beginnend bei 0 einführten und entschieden (verpasst), um null für enum nicht zu unterstützen. Später im Java1.7 (Juli 2011) Sie folgten (gezwungen) dieselbe Philosophie wie bei String (dh beim Generieren des Bytecodes wurde keine Nullprüfung durchgeführt, bevor die Methode hashcode() aufgerufen wurde).
Ich denke also, es läuft darauf hinaus, dass enum zuerst hereinkam und mit seinem ordinalen Beginn bei 0 implementiert wurde, aufgrund dessen sie keinen Nullwert im Switch-Block unterstützen konnten und später mit String beschlossen, dieselbe Philosophie zu erzwingen, dh Nullwert nicht im Schalterblock erlaubt.
TL;DR Mit String hätten sie sich um NPE kümmern können (verursacht durch den Versuch, Hashcode für null zu generieren), während sie die Java-Code-zu-Byte-Code-Konvertierung implementierten, sich aber schließlich dagegen entschieden.
Ein Schalter arbeitet mit den primitiven Datentypen byte, short, char und int. Es funktioniert auch mit Aufzählungstypen (diskutiert in Enum-Typen), der String-Klasse und einigen speziellen Klassen, die bestimmte primitive Typen umhüllen: Character, Byte, Short und Integer (diskutiert in Zahlen und Strings).
Seit null keinen Typ hat und keine Instanz von irgendetwas ist, funktioniert es nicht mit einer switch-Anweisung.
Amrith
Die Antwort lautet einfach: Wenn Sie einen Schalter mit einem Referenztyp (z. B. einem geschachtelten primitiven Typ) verwenden, tritt der Laufzeitfehler auf, wenn der Ausdruck null ist, da das Unboxing die NPE auslösen würde.
case null (was illegal ist) könnte also sowieso nie ausgeführt werden 😉
Das hätte man aber auch anders umsetzen können.
– Thilo
15. August 2013 um 23:40 Uhr
OK @Thilo, an dieser Umsetzung waren klügere Leute als ich beteiligt. Wenn Sie andere Möglichkeiten kennen, wie dies hätte implementiert werden können, würde ich gerne wissen, welche das sind [and I’m sure there are others] also teile…
– Amrith
16. August 2013 um 2:02 Uhr
Zeichenfolgen sind keine geschachtelten primitiven Typen, und die NPE tritt nicht auf, weil jemand versucht, sie zu „entpacken“.
– Thilo
16. August 2013 um 2:15 Uhr
@thilo, die anderen Möglichkeiten, dies zu implementieren, sind, was?
– Amrith
16. August 2013 um 10:30 Uhr
if (x == null) { // the case: null part }
– Thilo
19. August 2013 um 12:56 Uhr
13383500cookie-checkWarum unterstützt die String switch-Anweisung keinen Nullfall?yes
Keine schlüssige Antwort darauf, da wir nicht die Leute sind, die die Sprache gemacht haben. Alle Antworten werden reine Vermutungen sein.
– Sternchen
15. August 2013 um 23:22 Uhr
Ein Versuch, einzuschalten
null
wird eine Ausnahme verursachen. Führen Sie einif
prüfen Aufnull
dann gehen Sie in dieswitch
Aussage.– gparjani
15. August 2013 um 23:22 Uhr
Von dem JLS: Nach Einschätzung der Entwickler der Programmiersprache Java [throwing a
NullPointerException
if the expression evaluates tonull
at runtime] ist ein besseres Ergebnis, als die gesamte switch-Anweisung stillschweigend zu überspringen oder die Anweisungen (falls vorhanden) nach dem Standardlabel (falls vorhanden) auszuführen.– gparjani
15. August 2013 um 23:37 Uhr
@gparyani: Mach das zu einer Antwort. Das klingt sehr offiziell und endgültig.
– Thilo
15. August 2013 um 23:42 Uhr
@JeffGohlke: “Es gibt keine Möglichkeit, eine Warum-Frage zu beantworten, es sei denn, Sie sind die Person, die die Entscheidung getroffen hat.”… nun, gparyanis Kommentar beweist das Gegenteil
– Benutzer541686
15. August 2013 um 23:51 Uhr