vertical - swing fillers java
Cómo usar null en el interruptor (11)
Integer i = ...
switch (i){
case null:
doSomething0();
break;
}
En el código anterior, no puedo usar null en la declaración de mayúsculas y minúsculas. ¿Cómo puedo hacer esto de manera diferente? No puedo usar el default
porque entonces quiero hacer algo más.
Un conmutador funciona con los tipos de datos primitivos byte, short, char e int. También funciona con tipos enumerados (discutidos en Enum Types), la clase String y algunas clases especiales que envuelven ciertos tipos primitivos: Character, Byte, Short e Integer (discutido en Numbers and Strings).
Como null no tiene ningún tipo, y no es una instancia de nada, no funcionará con una instrucción switch.
Sencilla instrucción if dentro del interruptor:
//if ''i'' different from ''null'' return ''i'' else return ''DEFAULT'' switch(i != null ? i : DEFAULT) { case DEFAULT: break; }
O si enciende String:
String i = null; // equal to -> value != null ? value.toString() i = String.valueOf(i); : "null"; switch(i) { case "null": break; }
Última solución sin comprobación nula:
¡¡¡Sí!!! Me encanta usar TRY / CATCH o THROW nueva excepción como reemplazo IF / ELSE :)
Integer i = null;
try{
switch (i) {}
} catch(NullPointerException npx) {
// VM implementation specific message ->
// Caused by: java.lang.NullPointerException:
// Attempt to invoke virtual method
// ''int java.lang.Integer.intValue()'' on a null object reference
// you need to ensure child method don''t throw npx
// or throws some other exception in replacement of npx
if(npx.getMessage().indexOf("java.lang.Integer.intValue()")>=0) {
// handle null
}
}
editar - en respuesta:
Para su última solución: No programe Python en Java. - glglgl 15 feb a las 14:33
... Quise decir: en Python, las excepciones se consideran como un método de control de flujo normal (EAFP). En Java, se consideran como lo que dice su nombre: excepciones. Son bastante caros y deben usarse con cuidado. A diferencia de Python, use TRY / CATCH o THROW nueva excepción ya que el reemplazo IF / ELSE no es bueno aquí. - glglgl
Programación con excepciones
Se pueden usar excepciones para ayudar a escribir programas robustos ^ 1 . Proporcionan un enfoque organizado y estructurado a la solidez. Sin excepciones, un programa puede saturarse con sentencias if que prueban varias condiciones posibles de error. Con excepciones, es posible escribir una implementación limpia de un algoritmo que manejará todos los casos normales. Los casos excepcionales se pueden manejar en otro lugar, en una cláusula de captura de una declaración try.
Cuando un programa encuentra una condición excepcional y no tiene manera de manejarlo inmediatamente, el programa puede lanzar una excepción. En algunos casos, tiene sentido lanzar una excepción que pertenezca a una de las clases predefinidas de Java, como IllegalArgumentException o IOException. Sin embargo, si no hay una clase estándar que represente adecuadamente la condición excepcional, el programador puede definir una nueva clase de excepción. La nueva clase debe extender la clase estándar Throwable o una de sus subclases. En general, si el programador no desea requerir el manejo obligatorio de excepciones, la nueva clase extenderá RuntimeException (o una de sus subclases). Para crear una nueva clase de excepción comprobada, que requiere un manejo obligatorio, el programador puede extender una de las otras subclases de Excepción o puede extender la Excepción misma.
Aquí, por ejemplo, es una clase que amplía Exception y, por lo tanto, requiere el manejo obligatorio de excepciones cuando se usa:
public class ParseError extends Exception {
public ParseError(String message) {
// Create a ParseError object containing
// the given message as its error message.
super(message);
}
}
^ 1 un lugar donde la corrección y la solidez son importantes, y especialmente difíciles, en el procesamiento de los datos de entrada, ya sea que el usuario escriba los datos, los lea en un archivo o los reciba a través de una red.
incluso mejor aquí puedo darle un ejemplo para la aplicación de Android:
/**
* start catcher on main thread loop
*
* @param context - app or any other context
* @param handler - handler to post any background thread exceptions to ui thread
*/
public static void startCatcher(Context context, Handler handler) {
/** grab app default exception handler */
Thread.UncaughtExceptionHandler systemUncaughtHandler = Thread.getDefaultUncaughtExceptionHandler();
/** the following handler is used to catch exceptions thrown in background threads */
LogsExceptionHandler logsExceptionHandler = new LogsExceptionHandler(context, systemUncaughtHandler, handler);
/** set to app our handler as default one */
Thread.setDefaultUncaughtExceptionHandler(logsExceptionHandler);
/** loop while any exception in main looper */
while (true) try {
/** start message que loop */
App.log.info("Starting crash catch Looper");
Looper.loop();
/** if we exit unexpectedly set app default handler to initial one */
Thread.setDefaultUncaughtExceptionHandler(systemUncaughtHandler);
/** and throw Runtime exception */
throw new RuntimeException("Main thread loop unexpectedly exited");
/** catch */
} catch (LogsExceptionHandler.BackgroundException e) {
/** log and start exit hook same as for main ui caught exception */
String message = "Caught the exception in the background thread " + e.getThreadName() + ", TID: " + e.getTid() + " cause: " + e.getCause();
App.log.debug(message);
logsExceptionHandler.startHook(e);
} catch (Throwable e) {
/** log and start exit hook for caught exception */
App.log.debug("Caught the exception in the UI thread, e: {}", e);
logsExceptionHandler.startHook(e);
}
}
Algunas bibliotecas intentan ofrecer alternativas a la instrucción de switch
java incorporada. 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 de manera predeterminada, y $(null)
es perfectamente legal. Encuentro que esta es una solución más elegante que las alternativas, pero esto requiere java8 y una dependencia en la biblioteca de vavr ...
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 normalmente se alinea con una tabla de búsqueda en una base de datos (solo para tablas raramente actualizadas).
Sin embargo, cuando trato de usar findByTypeId
en una instrucción switch (de, muy probablemente, 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 indicado otros, esto da como resultado un switch(personType) {
NPE @ switch(personType) {
. Una solución (es decir, "solución") que comencé a implementar fue agregar un tipo UNKNOWN(-1)
.
public enum PersonType {
UNKNOWN(-1),
COOL_GUY(1),
JERK(2);
...
public static PersonType findByTypeId(int id) {
...
return UNKNOWN;
}
}
Ahora, no tiene que hacer una comprobación nula donde importa y puede elegir, o no, manejar tipos UNKNOWN
. (NOTA: -1
es un identificador improbable en un escenario empresarial, pero obviamente elija algo que tenga sentido para su caso de uso).
Esto no es posible con una instrucción switch
en Java. Compruebe null
antes del switch
:
if (i == null) {
doSomething0();
} else {
switch (i) {
case 1:
// ...
break;
}
}
No puede usar objetos arbitrarios en instrucciones de switch
* . El motivo por el que el compilador no se queja del modificador switch (i)
en el que i
es un Integer
es porque Java desunciona automáticamente el Integer
a un int
. Como ya dijimos Assylias, el unboxing lanzará una NullPointerException
cuando sea null
.
* Desde Java 7 puede usar String
en instrucciones de switch
.
Más información sobre el switch
(incluido el ejemplo con variable nula) en Oracle Docs - Switch
Los documentos Java declararon claramente que:
La prohibición de usar null como etiqueta de cambio evita que uno escriba código que nunca se puede ejecutar. Si la expresión del interruptor es de un tipo de referencia, como un tipo primitivo encuadrado o una enumeración, se producirá un error en tiempo de ejecución si la expresión se evalúa como nula en el tiempo de ejecución.
Debe verificar para null antes de la ejecución de la sentencia Swithch.
if (i == null)
case null: // will never be executed, therefore disallowed.
No puedes. Puede usar primitivas (int, char, short, byte) y String (Strings en java 7 solamente) en switch. las primitivas no pueden ser nulas.
Compruebe i
en condiciones separadas antes del cambio.
También puede usar String.valueOf((Object) nullableString)
como
switch (String.valueOf((Object) nullableString)) {
case "someCase"
//...
break;
...
case "null": // or default:
//...
break;
}
Ver interesante SO Q / A: ¿Por qué String.valueOf (null) arroja una NullPointerException
Tienes que hacer un
if (i == null) {
doSomething0();
} else {
switch (i) {
}
}
switch (String.valueOf (value)) {case "null": default:}
switch(i)
arrojará una NullPointerException si yo soy null
, porque tratará de desempaquetar el Integer
en un int
. Entonces, case null
, que pasa a ser ilegal, nunca se hubiera alcanzado de todos modos.
Debe verificar que no sea nulo antes de la instrucción de switch
.
switch ((i != null) ? i : DEFAULT_VALUE) {
//...
}