Quantcast
Channel: Planeta Código
Viewing all articles
Browse latest Browse all 2711

Blog Bitix: Lanzar excepciones checked como si fueran unchecked en Java

$
0
0
Java

No es una buena práctica al igual que al no recomendado antipatrón de inicialización de variables con dobles llaves pero en el uso de streams que aceptan lambdas es un rodeo a la limitación de no poder lanzar excepciones checked por no estar definida en su API.

En Java existen dos tipos de excepciones las checked que son de obligada captura o ser lanzadas y las unchecked que no son de obligada captura ni ser declaradas. Al usar streams y algunas interfaces funcionales de Java como Consumer que no lanzan excepciones el compilador generará un error de compilación si la implementación lanza una excepción.

En el siguiente código el compilador producirá un error de compilación ya que intenta lanzar una excepción pero la interfaz funcional que implementa no lo permite.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
importjava.util.List;publicclassMain1{publicstaticvoidmain(String[]args){List<String>list=List.of("a","b","c");list.stream().forEach(i->{if(i.equals("d")){thrownewException();}});}}
1
2
3
4
5
6
$ java Main1.java
Main1.java:9: error: unreported exception Exception; must be caught or declared to be thrown
throw new Exception();
^
1 error
error: compilation failed

Aunque en Java existen las excepciones checked y estas han de ser declaradas no es una limitación a nivel de la máquina virtual, se puede lanzar una excepción checked aunque no esté declarada. El siguiente código compila sin errores y se ejecutan, lanzándose la excepción aunque el método main() no la declare. Esto es debido a que en el método sneakyThrow()T es inferido como del tipo RuntimeException.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
publicclassMain2{@SuppressWarnings("unchecked")static<TextendsThrowable>voidsneakyThrow(Throwablet)throwsT{throw(T)t;}static<TextendsThrowable>voidnonSneakyThrow(Tt)throwsT{throwt;}publicstaticvoidmain(String[]args){Exceptione=newException();sneakyThrow(e);// No problems here
//nonSneakyThrow(e); // Error: Unhandled exception: java.lang.Exception
}}
1
2
3
$ java Main2.java
Exception in thread "main" java.lang.Exception
at Main2.main(Main2.java:15)

Con la clase Unsafe interna del JDK (que tampoco es recomendable usar porque en el futuro será eliminada) también es posible lanzar una excepción checked sin declararla, aunque Main3.getUnsafe().throwException(e) lanza una excepción el método main() no la declara.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
importjava.lang.reflect.Field;importsun.misc.Unsafe;publicclassMain3{privatestaticUnsafegetUnsafe(){try{Fieldfield=Unsafe.class.getDeclaredField("theUnsafe");field.setAccessible(true);return(Unsafe)field.get(null);}catch(Exceptione){thrownewRuntimeException(e);}}publicstaticvoidmain(String[]args){Exceptione=newException();Main.getUnsafe().throwException(e);}}
1
2
3
$ java Main3.java
Exception in thread "main" java.lang.Exception
at Main3.main(Main3.java:18)

Es posible lanzar excepciones checked como si fuesen uncheked, no es una buena práctica ya que no permite al compilador cumplir con la tarea a la que está destinada que es detectar errores en tiempo de compilación potenciales problemas además de no indicar en la API que un método lanza una excepción que debería se tratada. En la librería Vavr con la clase Try se puede usar un método que lanza una excepción, tratarla si se produce y convertir el método en uno que no lanza excepciones adecuado para el uso en los streams.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
importjava.util.List;importio.vavr.control.Try;publicclassMain4{publicstaticvoidaction(Stringstring)throwsException{if(i.equals("d")){thrownewException();}}publicstaticvoidmain(String[]args){List<String>list=List.of("a","b","c");list.stream().forEach(i->{Try.of(()->{action(i);});});}}

La opción más recomendable es crear una clase como Try o usar la de la librería Vavr en vez de una de las posibilidades no recomendadas anteriores.


Viewing all articles
Browse latest Browse all 2711