Verwendung von null in switch

202
Integer i = ...

switch (i){
    case null:
        doSomething0();
        break;    
    }

Im obigen Code kann ich null in der switch case-Anweisung nicht verwenden. Wie kann ich das anders machen? Ich kann nicht verwenden, defaultweil ich dann etwas anderes tun möchte.

hudi
quelle
9
vor dem Schalter auf Null prüfen, wenn (i == null) {// dosomething}
Nagaraju Badaeni
8
Dies würde den Schalter tatsächlich nützlich machen. Andere Mustervergleichssprachen funktionieren auf diese Weise.
Pyrolistical

Antworten:

276

Dies ist mit einer switchAnweisung in Java nicht möglich . Überprüfen Sie nullvor switch:

if (i == null) {
    doSomething0();
} else {
    switch (i) {
    case 1:
        // ...
        break;
    }
}

Sie können keine beliebigen Objekte in switchAnweisungen * verwenden . Der Grund, warum sich der Compiler nicht darüber beschwert, switch (i)wo isich ein Integerbefindet, liegt darin, dass Java das Integerzu einem automatisch entpackt int. Wie assylias bereits gesagt, wird das Unboxing eines Wurf , NullPointerExceptionwenn iist null.

* Seit Java 7 können Sie Stringin switchAnweisungen verwenden.

Weitere Informationen zu switch(einschließlich Beispiel mit Nullvariable) in Oracle Docs - Switch

Jesper
quelle
16
Sie können auch Aufzählungen in switch-Anweisungen verwenden.
Joriki
27
Es ist sinnvoll, dass Sie aufgrund des Unboxing keine Null-Ganzzahl oder eine andere Wrapper-Klasse verwenden können. Aber was ist mit Enums und Strings? Warum können sie nicht null sein?
Luan Nico
9
Ich verstehe nicht, warum ein Kurzschluss von Null, der dem "Standard" -Fall oder einem Sonderfall für einen Nullschalter zugeordnet ist, für Strings nicht implementiert wurde. Es macht die Verwendung von Schaltern zur Vereinfachung des Codes sinnlos, da Sie immer eine Nullprüfung durchführen müssen. Ich sage nicht, dass Vereinfachung die einzige Verwendung für Schalter ist.
Reimius
3
@Reimius Sie müssen nicht immer eine Nullprüfung durchführen. Wenn Sie den Code Verträge respektieren , dass Sie Ihre Methoden geben, können Sie fast verwalten immer nicht haben Ihren Code mit null Kontrollen laden. Asserts zu verwenden ist jedoch immer schön.
Joffrey
Ich würde auch gerne die Antwort auf die Anfrage von @ LuanNico wissen. Es erscheint unvernünftig, dass nullbei der Arbeit mit Stringund enumTypen kein gültiger Fall sein kann . Vielleicht enumberuht die Implementierung darauf, ordinal()hinter die Kulissen zu rufen (obwohl dies nulldennoch eine Ordnungszahl von -1 ist?), Und die StringVersion verwendet etwas unter Verwendung eines intern()Zeigervergleichs (oder basiert auf etwas, das eine Dereferenzierung von unbedingt erforderlich macht) Objekt)?
aroth
98
switch ((i != null) ? i : DEFAULT_VALUE) {
        //...
}
Tetsuo
quelle
sauberer Weg als mit einem Extra, wenn sonst
Vivek Agrawal
40

switch(i)wird eine NullPointerException auslösen, wenn i ist null, weil es versucht, die Integerin eine zu entpacken int. Also case null, die illegal sein geschieht, würde sowieso nie erreicht worden sind.

Sie müssen vor der switchAnweisung überprüfen, ob i nicht null ist .

Assylien
quelle
23

In Java-Dokumenten wurde klargestellt, dass:

Das Verbot, null als Switch-Label zu verwenden, verhindert, dass man Code schreibt, der niemals ausgeführt werden kann. Wenn der switch-Ausdruck von einem Referenztyp ist, z. B. ein primitiver Typ mit Box oder eine Aufzählung, tritt ein Laufzeitfehler auf, wenn der Ausdruck zur Laufzeit als null ausgewertet wird.

Sie müssen vor der Ausführung der Swithch-Anweisung auf null prüfen.

if (i == null)

Siehe Die Switch-Anweisung

case null: // will never be executed, therefore disallowed.
Shehzad
quelle
1
Die Javadocs unter Ihrem Link sagen nicht mehr "Das Verbot, null als Schalterbezeichnung zu verwenden [usw.]".
Patrick M
14

Gegeben:

public enum PersonType {
    COOL_GUY(1),
    JERK(2);

    private final int typeId;
    private PersonType(int typeId) {
        this.typeId = typeId;
    }

    public final int getTypeId() {
        return typeId;
    }

    public static PersonType findByTypeId(int typeId) {
        for (PersonType type : values()) {
            if (type.typeId == typeId) {
                return type;
            }
        }
        return null;
    }
}

Für mich stimmt dies normalerweise mit einer Nachschlagetabelle in einer Datenbank überein (nur für selten aktualisierte Tabellen).

Wenn ich jedoch versuche, findByTypeIdeine switch-Anweisung zu verwenden (höchstwahrscheinlich aus Benutzereingaben) ...

int userInput = 3;
PersonType personType = PersonType.findByTypeId(userInput);
switch(personType) {
case COOL_GUY:
    // Do things only a cool guy would do.
    break;
case JERK:
    // Push back. Don't enable him.
    break;
default:
    // I don't know or care what to do with this mess.
}

... wie andere angegeben haben, führt dies zu einem NPE @ switch(personType) {. Eine Problemumgehung (dh "Lösung"), die ich implementiert habe, war das Hinzufügen eines UNKNOWN(-1)Typs.

public enum PersonType {
    UNKNOWN(-1),
    COOL_GUY(1),
    JERK(2);
    ...
    public static PersonType findByTypeId(int id) {
        ...
        return UNKNOWN;
    }
}

Jetzt müssen Sie nicht mehr null prüfen, wo es darauf ankommt, und Sie können wählen, ob UNKNOWNTypen behandelt werden sollen oder nicht . (HINWEIS: -1ist eine unwahrscheinliche Kennung in einem Geschäftsszenario, wählen Sie jedoch offensichtlich etwas, das für Ihren Anwendungsfall sinnvoll ist.)

Beez
quelle
2
UNKNOWNist die beste Lösung dafür, die ich je gesehen habe, und überwinde Nullchecks.
Membersound
5

Du musst eine machen

if (i == null) {
   doSomething0();
} else {
   switch (i) {
   }
}
Kai
quelle
4

Einige Bibliotheken versuchen, Alternativen zur integrierten Java- switchAnweisung anzubieten . Vavr ist einer von ihnen, sie verallgemeinern es auf Mustervergleich.

Hier ist ein Beispiel aus ihrer Dokumentation :

String s = Match(i).of(
    Case($(1), "one"),
    Case($(2), "two"),
    Case($(), "?")
);

Sie können jedes Prädikat verwenden, aber sie bieten viele von ihnen sofort an und $(null)sind vollkommen legal. Ich finde das eine elegantere Lösung als die Alternativen, aber dies erfordert Java8 und eine Abhängigkeit von der Vavr-Bibliothek ...

Emmanuel Touzery
quelle
2

Sie können auch String.valueOf((Object) nullableString) gerne verwenden

switch (String.valueOf((Object) nullableString)) {
case "someCase"
    //...
    break;
...
case "null": // or default:
    //...
        break;
}

Siehe interessante SO Q / A: Warum löst String.valueOf (null) eine NullPointerException aus?

oikonomopo
quelle
2
switch (String.valueOf(value)){
    case "null":
    default: 
}
l0v3
quelle
0

Das kannst du nicht. Sie können Primitive (int, char, short, byte) und String (Strings nur in Java 7) in switch verwenden. Grundelemente können nicht null sein.
Überprüfen Sie iin einem separaten Zustand vor dem Einschalten.

Mikita Belahlazau
quelle
4
Sie können auch Aufzählungen verwenden.
Karu
5
Wenn die Aufzählung null ist, haben Sie das gleiche Problem. Übrigens ist es ziemlich seltsam, dass der Switch nicht mit Null umgehen kann, da er eine Standardklausel hat
1
@LeonardoKenji Die Standardklausel hat eigentlich nichts mit null zu tun. Was auch immer Sie einschalten, es wird dereferenziert, um andere Fälle zu überprüfen, sodass die Standardklausel den Nullfall nicht behandelt (eine NullPointerException wird ausgelöst, bevor sie eine Chance dazu hat).
Ben
2
Ich denke, er meinte, die Standardklausel sollte null als jeden anderen möglichen Aufzählungswert behandeln, der vom vorherigen Fall nicht erfasst wurde
Leo
0

Überlegen Sie einfach, wie der SCHALTER funktionieren könnte.

  • Im Fall von Grundelementen wissen wir, dass es mit NPE beim Auto-Boxen fehlschlagen kann
  • Bei String oder enum wird möglicherweise die Methode equals aufgerufen, für die offensichtlich ein LHS-Wert erforderlich ist, für den equals aufgerufen wird. Da für eine Null keine Methode aufgerufen werden kann, kann der Switch nicht mit Null umgehen.
Puneet
quelle
0

Basierend auf der Antwort von @tetsuo mit Java 8:

Integer i = ...

switch (Optional.ofNullable(i).orElse(DEFAULT_VALUE)) {
    case DEFAULT_VALUE:
        doDefault();
        break;    
}
Kalbater
quelle