objeto - interface java
Lanzar y atrapar una excepción, o usar instanceof? (4)
Le recomiendo que utilice un objeto plano para representar su "restricción". Si depende de usted una interfaz de marcado (por ejemplo, un Message
) o una java.lang.String
. Las excepciones no están destinadas a usarse como usted pretende, incluso si cualquiera de las dos podría funcionar (esperaría que la segunda sea más rápida, pero una optimización prematura ...).
Tengo una excepción en una variable (no lanzada).
¿Cuál es la mejor opción?
Exception exception = someObj.getExcp();
try {
throw exception;
} catch (ExceptionExample1 e) {
e.getSomeCustomViolations();
} catch (ExceptionExample2 e) {
e.getSomeOtherCustomViolations();
}
o
Exception exception = someObj.getExcp();
if (exception instanceof ExceptionExample1) {
exception.getSomeCustomViolations();
} else if (exception instanceof ExceptionExample2) {
exception.getSomeOtherCustomViolations();
}
Odio explotar la burbuja de todos, pero usar try/catch
es más rápido . Eso no quiere decir que sea la forma "correcta", pero si el rendimiento es clave, ese es el ganador. Aquí están los resultados del siguiente programa:
Ejecutar 1
- Sub-ejecución 1: Instancia de: 130 ms
- Sub-ejecución 1: Prueba / captura: 118 ms
- Sub-ejecución 2: Instancia de: 96 ms
- Sub-ejecución 2: Prueba / captura: 93 ms
- Sub-ejecución 3: Instancia de: 100 ms
- Sub-ejecución 3: Prueba / captura: 99 ms
Ejecutar 2
- Sub-ejecución 1: Instancia de: 140 ms
- Sub-ejecución 1: Prueba / captura: 111 ms
- Sub-ejecución 2: Instancia de: 92 ms
- Sub-ejecución 2: Prueba / captura: 92 ms
- Sub-ejecución 3: Instancia de: 105 ms
- Sub-ejecución 3: Prueba / captura: 95 ms
Corre 3
- Sub-ejecución 1: Instancia de: 140 ms
- Sub-ejecución 1: Prueba / captura: 135 ms
- Sub-ejecución 2: Instancia de: 107 ms
- Sub-ejecución 2: Prueba / captura: 88 ms
- Sub-ejecución 3: Instancia de: 96 ms
- Sub-ejecución 3: Prueba / captura: 90 ms
Entorno de prueba
- Java: 1.7.0_45
- Mac OSX Mavericks
Al descontar sub-ejecuciones de calentamiento de cada ejecución, el método instanceof
solo logra en el mejor de los casos el rendimiento de try/catch
. El promedio (descontando los calentamientos) del método de instanceof
es de 98 ms y el promedio de try/catch
es de 92 ms.
Tenga en cuenta que no varié el orden en que se probó cada método. Siempre probé un bloque de instanceof
luego un bloque de try/catch
. Me encantaría ver otros resultados que contradigan o confirmen estos hallazgos.
public class test {
public static void main (String [] args) throws Exception {
long start = 0L;
int who_cares = 0; // Used to prevent compiler optimization
int tests = 100000;
for ( int i = 0; i < 3; ++i ) {
System.out.println("Testing instanceof");
start = System.currentTimeMillis();
testInstanceOf(who_cares, tests);
System.out.println("instanceof completed in "+(System.currentTimeMillis()-start)+" ms "+who_cares);
System.out.println("Testing try/catch");
start = System.currentTimeMillis();
testTryCatch(who_cares, tests);
System.out.println("try/catch completed in "+(System.currentTimeMillis()-start)+" ms"+who_cares);
}
}
private static int testInstanceOf(int who_cares, int tests) {
for ( int i = 0; i < tests; ++i ) {
Exception ex = (new Tester()).getException();
if ( ex instanceof Ex1 ) {
who_cares = 1;
} else if ( ex instanceof Ex2 ) {
who_cares = 2;
}
}
return who_cares;
}
private static int testTryCatch(int who_cares, int tests) {
for ( int i = 0; i < tests; ++i ) {
Exception ex = (new Tester()).getException();
try {
throw ex;
} catch ( Ex1 ex1 ) {
who_cares = 1;
} catch ( Ex2 ex2 ) {
who_cares = 2;
} catch ( Exception e ) {}
}
return who_cares;
}
private static class Ex1 extends Exception {}
private static class Ex2 extends Exception {}
private static java.util.Random rand = new java.util.Random();
private static class Tester {
private Exception ex;
public Tester() {
if ( rand.nextBoolean() ) {
ex = new Ex1();
} else {
ex = new Ex2();
}
}
public Exception getException() {
return ex;
}
}
}
Recomiendo usar instanceof
ya que probablemente sea más rápido. Lanzar una excepción es una operación complicada y costosa. Las JVM están optimizadas para ser rápidas en el caso de que no se produzcan excepciones. Las excepciones deben ser excepcionales.
Tenga en cuenta que la técnica de throw
probablemente no se compilará como se muestra, si su tipo de excepción es una excepción marcada, el compilador se quejará de que debe capturar ese tipo o declararlo como lanzado (correspondiente a una cláusula else { ... }
si use la técnica instanceof
), que puede o no ser útil, dependiendo de cómo quiera manejar las excepciones que no son uno de los subtipos específicos.
También puede usar el polimorfismo creando una interfaz para sus excepciones personalizadas que contiene el método getCustomViolation (). Luego, cada excepción personalizada implementaría esa interfaz y ese método.