Come utilizzare null in switch


202
Integer i = ...

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

Nel codice sopra non posso usare null nell'istruzione switch case. Come posso fare diversamente? Non posso usarlo defaultperché poi voglio fare qualcos'altro.


9
prima del cambio verificare la condizione nulla se (i == null) {// dosomething}
Nagaraju Badaeni,

8
Ciò renderebbe effettivamente utile l'interruttore. Altre lingue di corrispondenza dei modelli funzionano in questo modo.
Pirolistico il

Risposte:


277

Questo non è possibile con switchun'istruzione in Java. Verificare nullprima di switch:

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

Non è possibile utilizzare oggetti arbitrari nelle switchistruzioni * . Il motivo per cui il compilatore non si lamenta di switch (i)dove si itrova an Integerè perché Java si decomprime automaticamente Integerin an int. Come assylias già detto, l'unboxing sarà gettare un NullPointerExceptionquando iè null.

* Da Java 7 è possibile utilizzare Stringnelle switchistruzioni.

Ulteriori informazioni switch(incluso l'esempio con variabile null) in Oracle Docs - Switch


16
Puoi anche usare enum nelle istruzioni switch.
Joriki,

27
Ha senso che non è possibile utilizzare un numero intero Null o un'altra classe Wrapper, a causa della decompressione. Ma che dire di enumerazioni e archi? Perché non possono essere nulli?
Luan Nico,

9
Non capisco perché non sia stato implementato per le stringhe un corto circuito di null associato al caso "predefinito" o un caso speciale per uno switch null. Rende inutile l'uso degli switch per semplificare il codice poiché è sempre necessario eseguire un controllo null. Non sto dicendo che la semplificazione sia l'unico uso per gli switch.
Reimius,

3
@Reimius non devi sempre fare un controllo nullo. Se rispetti i contratti di codice che dai ai tuoi metodi, puoi quasi sempre riuscire a non ingombrare il tuo codice con controlli nulli. L'uso degli asserti è sempre bello, comunque.
Joffrey,

Mi piacerebbe anche sapere la risposta alla domanda di @ LuanNico. Sembra irragionevole che nullnon può essere un caso valido quando si lavora con Stringe enumtipi. Forse l' enumimplementazione si basa sul richiamo ordinal()dietro le quinte (anche se anche così, perché non trattare nullcome un 'ordinale' di -1?), E la Stringversione fa qualcosa usando intern()e il confronto puntatore (o si basa su qualcosa che richiede rigorosamente il dereferenziamento di un oggetto)?
aroth

98
switch ((i != null) ? i : DEFAULT_VALUE) {
        //...
}

un modo più pulito rispetto all'utilizzo di un extra, se non altro
Vivek Agrawal,

40

switch(i)genererà una NullPointerException se lo è null, perché tenterà di decomprimere il file Integerin un int. Quindi case null, che risulta illegale, non sarebbe mai stato raggiunto comunque.

È necessario verificare che non sia null prima della switchdichiarazione.


23

I documenti Java affermavano chiaramente che:

Il divieto di usare null come etichetta switch impedisce di scrivere codice che non può mai essere eseguito. Se l'espressione switch è di un tipo di riferimento, ad esempio un tipo primitivo inscatolato o un enum, si verificherà un errore di runtime se l'espressione restituisce null in fase di runtime.

È necessario verificare la null per l'esecuzione dell'istruzione Swithch.

if (i == null)

Vedi l'istruzione Switch

case null: // will never be executed, therefore disallowed.

1
I javadocs sul tuo link non dicono più "Il divieto di usare null come etichetta switch [ecc.]".
Patrick M,


14

Dato:

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;
    }
}

Per me, questo in genere si allinea con una tabella di ricerca in un database (solo per tabelle raramente aggiornate).

Tuttavia, quando provo a utilizzare findByTypeIdin un'istruzione switch (da, molto probabilmente, l'input dell'utente) ...

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.
}

... come altri hanno affermato, questo si traduce in un NPE @ switch(personType) {. Una soluzione (ovvero "soluzione") che ho iniziato a implementare è stata l'aggiunta di un UNKNOWN(-1)tipo.

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

Ora, non è necessario eseguire il controllo null dove conta e puoi scegliere di gestire i UNKNOWNtipi o meno . (NOTA: -1è un identificatore improbabile in uno scenario aziendale, ma ovviamente scegli qualcosa che abbia senso per il tuo caso d'uso).


2
UNKNOWNè la migliore soluzione su questo che abbia mai visto e superare i controlli null.
membri del

5

Devi fare un

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

4

Alcune librerie tentano di offrire alternative switchall'istruzione java integrata . Vavr è uno di questi, lo generalizzano alla corrispondenza dei modelli.

Ecco un esempio dalla loro documentazione :

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

Puoi usare qualsiasi predicato, ma ne offrono molti fuori dagli schemi ed $(null)è perfettamente legale. Trovo che questa sia una soluzione più elegante delle alternative, ma ciò richiede java8 e una dipendenza dalla libreria vavr ...



2
switch (String.valueOf(value)){
    case "null":
    default: 
}

0

Non puoi. È possibile utilizzare primitive (int, char, short, byte) e String (solo stringhe in Java 7) in switch. le primitive non possono essere nulle.
Controllare iin condizioni separate prima di passare.


4
Puoi anche usare enum.
Karu,

5
se l'enum è nullo, avrai lo stesso problema. A proposito, è piuttosto strano che switch non sia in grado di gestire null, poiché ha una clausola predefinita

1
@LeonardoKenji La clausola predefinita non ha nulla a che fare con null; qualunque cosa tu stia accendendo, verrà verificato per verificare eventuali altri casi, quindi la clausola predefinita non gestirà il caso null (viene lanciata una NullPointerException prima che abbia una possibilità).
Ben

2
Penso che intendesse dire che la clausola di default dovrebbe gestire null come qualsiasi altro possibile valore enum che non è stato preso dal caso precedente
Leo

0

Considera solo come potrebbe funzionare SWITCH,

  • nel caso di primitivi sappiamo che può fallire con NPE per l'auto-boxing
  • ma per String o enum , potrebbe essere invocare il metodo equals, che ovviamente ha bisogno di un valore LHS sul quale viene invocato uguale. Pertanto, dato che nessun metodo può essere invocato su un null, l' opzione switch non può gestire null.

0

Basato sulla risposta di @tetsuo, con java 8:

Integer i = ...

switch (Optional.ofNullable(i).orElse(DEFAULT_VALUE)) {
    case DEFAULT_VALUE:
        doDefault();
        break;    
}
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.