java - validacion - valor predeterminado celda excel
¿Por qué se requiere el valor predeterminado para un cambio en una enumeración en este código? (6)
Como se ha indicado, debe devolver un valor y el compilador no asume que la enumeración no puede cambiar en el futuro. Por ejemplo, puede crear otra versión de la enumeración y usarla sin volver a compilar el método.
Nota: hay un tercer valor para xyz
que es nulo.
public static String testSwitch(XYZ xyz) {
if(xyz == null) return "null";
switch(xyz){
case A:
return "A";
case B:
return "B";
}
return xyz.getName();
}
Este ha el mismo resultado que
public static String testSwitch(XYZ xyz) {
return "" + xyz;
}
La única forma de evitar una devolución es lanzar una excepción.
public static String testSwitch(XYZ xyz) {
switch(xyz){
case A:
return "A";
case B:
return "B";
}
throw new AssertionError("Unknown XYZ "+xyz);
}
Normalmente, el valor predeterminado no es necesario en una instrucción de cambio. Sin embargo, en la siguiente situación, el código se compila correctamente solo cuando elimino el comentario de la declaración predeterminada. ¿Alguien puede explicar por qué?
public enum XYZ {A,B};
public static String testSwitch(XYZ xyz)
{
switch(xyz)
{
case A:
return "A";
case B:
//default:
return "B";
}
}
Creo que esto se explica por las reglas de asignación definidas de JLS para las instrucciones de switch
( JLS 16.2.9 ) que establecen lo siguiente:
"V es [un] asignado después de una instrucción de cambio si todos los siguientes son verdaderos:
- O hay una etiqueta predeterminada en el bloque de conmutación o V se asigna [un] después de la expresión de conmutación.
Si luego aplicamos esto a la V
nocional que es el valor de retorno del método, podemos ver que si no hay una rama por default
, el valor no estaría asignado teóricamente.
OK ... estoy extrapolando reglas de asignación definidas para cubrir los valores de retorno, y tal vez no lo hagan. Pero el hecho de que no haya podido encontrar algo más directo en la especificación no significa que no esté allí :-)
Hay otra razón (más sólida) por la que el compilador tiene que dar un error. Se deriva de las reglas de compatibilidad binarias para enum
( JLS 13.4.26 ) que establecen lo siguiente:
"Agregar o reordenar constantes de un tipo de enumeración no romperá la compatibilidad con los binarios preexistentes".
Entonces, ¿cómo se aplica eso en este caso? Supongamos que al compilador se le permitió inferir que la sentencia de ejemplo de cambio de OP siempre devolvía algo. ¿Qué sucede si el programador ahora cambia la enum
para agregar una constante adicional? De acuerdo con las reglas de compatibilidad binaria de JLS, no hemos roto la compatibilidad binaria. Sin embargo, el método que contiene la instrucción switch
ahora puede (dependiendo de su argumento) devolver un valor indefinido. No se puede permitir que eso suceda, por lo tanto, el cambio debe ser un error de compilación.
Debido a que el compilador no puede adivinar que solo hay dos valores en la enum
y lo obliga a devolver el valor del método. (Sin embargo, no sé por qué no puede adivinar, tal vez tiene algo con la reflexión).
Hay un contrato que este método tiene para devolver una Cadena a menos que lance una Excepción. Y cada vez no se limita a aquellos casos en los que el valor de xyz
es igual a XVZ.A
o XYZ.B
Aquí hay otro ejemplo, donde es obvio , que el código se ejecutará correctamente pero donde tenemos un error de tiempo de compilación por la misma razón:
public boolean getTrue() {
if (1 == 1) return true;
}
No es cierto que tenga que agregar una declaración predeterminada, es cierto, que debe devolver un valor en cualquier momento. Entonces, agregue una declaración por defecto o agregue una declaración de retorno después del bloque de cambio.
La razón por la que tiene que descomentar el default
es que su función dice que devuelve una String
, pero si solo tiene etiquetas de case
definidas para A
y B
entonces la función no devolverá un valor si pasa cualquier otra cosa. Java requiere que todas las funciones que indican que devuelven un valor realmente devuelvan un valor en todas las rutas de control posibles, y en su caso, el compilador no está convencido de que todas las entradas posibles tengan un valor devuelto.
Creo (y no estoy seguro de esto) que la razón de esto es que incluso si cubre todos sus casos de enum
, el código podría fallar en algunos casos. En particular, suponga que compila el código Java que contiene esta instrucción de modificador (que funciona bien), luego, cambie la enum
para que haya una tercera constante, digamos C
, pero no switch
compilar el código con el switch
declaración en el mismo. Ahora, si intenta escribir código Java que usa la clase compilada previamente y pasa C
en esta declaración, entonces el código no tendrá un valor para devolver, violando el contrato de Java de que todas las funciones siempre devuelven valores.
En términos técnicos, creo que la razón real es que el verificador de bytecode JVM siempre rechaza las funciones en las que hay una ruta de control que cae del final de una función (consulte §4.9.2 de la especificación de JVM ), y por lo tanto si el código si se compilara, la JVM lo rechazaría en el tiempo de ejecución de todos modos. Por lo tanto, el compilador le da el error de informar que existe un problema.
default: throw new AssertionError();