Cómo usar nulo en el interruptor


202
Integer i = ...

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

En el código anterior, no puedo usar nulo en la declaración de cambio de caso. ¿Cómo puedo hacer esto de manera diferente? No puedo usar defaultporque quiero hacer otra cosa.


9
antes del cambio, verifique la condición nula si (i == nulo) {// dosomething}
Nagaraju Badaeni

8
Esto realmente haría que el cambio sea útil. Otros lenguajes de coincidencia de patrones funcionan de esta manera.
Pirolístico

Respuestas:


277

Esto no es posible con una switchdeclaración en Java. Consulte nullantes de switch:

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

No puede usar objetos arbitrarios en las switchdeclaraciones * . La razón por la que el compilador no se queja de switch (i)dónde ies un Integeres porque Java desempaqueta automáticamente Integera un int. Como ya dijo asilias, el unboxing arrojará un NullPointerExceptioncuándo ies null.

* Desde Java 7 puede usar Stringen switchdeclaraciones.

Más información switch(incluido el ejemplo con variable nula) en Oracle Docs - Switch


16
También puede usar enumeraciones en las declaraciones de cambio.
joriki

27
Tiene sentido que no pueda usar un entero nulo u otra clase de envoltura, debido al desempaquetado. ¿Pero qué pasa con las enumeraciones y las cadenas? ¿Por qué no pueden ser nulos?
Luan Nico

9
No entiendo por qué no se implementó un cortocircuito de nulo en el caso "predeterminado" o un caso especial para un interruptor nulo para Strings. Hace que el uso de interruptores para simplificar el código no tenga sentido ya que siempre debe hacer una verificación nula. Sin embargo, no digo que la simplificación sea el único uso para los interruptores.
Reimius

3
@Reimius, no siempre tienes que hacer una comprobación nula. Si respeta los contratos de código que le da a sus métodos, casi siempre puede lograr que su código no esté lleno de verificaciones nulas. Sin embargo, usar afirmaciones siempre es bueno.
Joffrey

También me gustaría saber la respuesta a la consulta de @ LuanNico. Parece irrazonable que nullno pueda ser un caso válido cuando se trabaja con Stringy enumtipos. Quizás la enumimplementación se basa en llamar ordinal()detrás de escena (aunque aún así, ¿por qué no tratar nullcomo si tuviera un 'ordinal' de -1?), Y la Stringversión hace algo usando intern()una comparación de puntero (o de lo contrario se basa en algo que estrictamente requiere desreferenciar un objeto)?
Aroth


40

switch(i)lanzará una NullPointerException si lo es null, porque intentará desempaquetar Integeren un int. Entoncescase null , lo que resulta ser ilegal, nunca habría sido alcanzado de todos modos.

Debe verificar que no sea nulo antes de la switchdeclaración.


23

Los documentos de Java declararon claramente que:

La prohibición de usar nulo como etiqueta de interruptor evita que uno escriba código que nunca se puede ejecutar. Si la expresión de cambio es de un tipo de referencia, como un tipo primitivo en caja o una enumeración, se producirá un error en tiempo de ejecución si la expresión se evalúa como nula en tiempo de ejecución.

Debe tener que verificar nulo antes de la ejecución de la declaración Swithch.

if (i == null)

Ver la declaración de cambio

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

1
Los javadocs en su enlace ya no dicen "La prohibición de usar nulo como etiqueta de interruptor [etc.]".
Patrick M


14

Dado:

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

Para mí, esto generalmente se alinea con una tabla de búsqueda en una base de datos (solo para tablas que rara vez se actualizan).

Sin embargo, cuando trato de usar findByTypeIden una declaración de cambio (de, muy probablemente, la entrada del usuario) ...

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

... como han dicho otros, esto da como resultado un NPE @ switch(personType) {. Una solución alternativa (es decir, "solución") que comencé a implementar fue agregar un UNKNOWN(-1)tipo.

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

Ahora, no tiene que hacer una verificación nula donde cuenta y puede elegir manejar o no los UNKNOWNtipos. (NOTA: -1es un identificador poco probable en un escenario empresarial, pero obviamente elige algo que tenga sentido para su caso de uso).


2
UNKNOWNes la mejor solución que he visto en mi vida y supero los nullchecks.
membersound

5

Tienes que hacer un

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

4

Algunas bibliotecas intentan ofrecer alternativas a la switchdeclaración integrada de Java . Vavr es uno de ellos, lo generalizan a la coincidencia de patrones.

Aquí hay un ejemplo de su documentación :

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

Puede usar cualquier predicado, pero ofrecen muchos de ellos listos para usar, y $(null)es perfectamente legal. Me parece una solución más elegante que las alternativas, pero esto requiere java8 y una dependencia de la biblioteca vavr ...



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

0

No puedes Puede usar primitivas (int, char, short, byte) y String (Strings en java 7 solamente) en el switch. Las primitivas no pueden ser nulas.
Compruebe ien condiciones separadas antes del interruptor.


44
También puedes usar enumeraciones.
Karu

55
Si la enumeración es nula, tendrá el mismo problema. Por cierto, es bastante extraño que el interruptor no pueda manejar nulo, ya que tiene una cláusula predeterminada

1
@LeonardoKenji La cláusula predeterminada realmente no tiene nada que ver con nulo; lo que sea que esté activando, se desreferenciará para verificar cualquier otro caso, por lo que la cláusula predeterminada no manejará el caso nulo (se lanza una NullPointerException antes de que tenga la oportunidad).
Ben

2
Creo que se refería a que la cláusula predeterminada debería manejar nulo como cualquier otro valor de enumeración posible que no fue detectado por el caso anterior
Leo

0

Solo considere cómo podría funcionar el INTERRUPTOR,

  • en caso de primitivas, sabemos que puede fallar con NPE para el auto-boxeo
  • pero para String o enum , podría estar invocando el método equals, que obviamente necesita un valor LHS en el que se invoque equals. Entonces, dado que no se puede invocar ningún método en un valor nulo, el interruptor no puede manejar nulo.

0

Basado en la respuesta @tetsuo, con java 8:

Integer i = ...

switch (Optional.ofNullable(i).orElse(DEFAULT_VALUE)) {
    case DEFAULT_VALUE:
        doDefault();
        break;    
}
Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.