Checked Exceptions weiter werfen ohne Wrappen oder throws-Klausel


#1

Oft ruft man Code auf, der checked Exceptions schmeißen kann. In einigen Situationen kann in so einem Fall das Programm nicht weiterlaufen und soll beendet werden. Ein gängiges Verfahren dafür ist, die checked Exception in eine RuntimeException (oder Unterklasse wie IllegalStateException) zu wrappen und dann weiter zu werfen. Damit erspart man sich die throws-Klausel in der Methodensignatur. Beispiel:
Java Code:

[ol]
[li]public Stream linesFromPath(Path path) {[/li]>
[li] try {[/li]>
[li] return Files.lines(path);[/li]>
[li] } catch (IOException e) {[/li]>
[li] throw new IllegalStateException(e);[/li]>
[li] }[/li]>
[li]}[/li]>
[/ol]

Soweit nichts Weltbewegendes. An dem Verfahren sind zwei Sachen unschön. 1. Erzeugung eines im Grunde unnötigen Objekts, der IllegalStateException. 2. Die wahre Fehlerursache muss über getCause() aus der IllegalStateException herausgefuddelt werden.

Wenn man sich etwas mit dem Thema checked/unchecked Throwables beschäftigt und damit, wie Java damit umgeht, so stellt man fest, dass der Unterschied checked/unchecked etwas ist, das der Compiler prüft. Zur Laufzeit existiert dieser Unterschied nicht mehr. Es stellt sich die Frage, ob man eine checked Exception an der Compilerprüfung vorbei schmuggeln kann. Mit dem sonst viel gescholtenen Type Erasure bei Generics lässt sich das tatsächlich bewerkstelligen:
Java Code:

[ol]
[li]public Stream linesFromPath(Path path) {[/li]>
[li] try {[/li]>
[li] return Files.lines(path);[/li]>
[li] } catch (IOException e) {[/li]>
[li] throwSneaky(e);[/li]>
[li] }[/li]>
[li] // Compiler ausgetrickst[/li]>
[li] return null;[/li]>
[li]}[/li]>
[li] [/li]>
[li]@SuppressWarnings(“unchecked”)[/li]>
[li]static void throwSneaky(Exception e) throws E {[/li]>
[li] throw (E) e;[/li]>
[li]}[/li]>
[/ol]

Auf diese Weise kann die checked Exception direkt weiter geworfen werden, ohne die Notwendigkeit, sie zu wrappen oder eine throws-Klausel zu definieren. Unschön ist allerdings, dass durch das Austricksen des Compilers im catch-Block kein throw mehr steht. Man muss also ein return Statement einbauen, das nie erreicht wird.

Diese Idee stammt nicht von mir. Ich bin auf stackoverflow darüber gestolpert. Ich wollte sie hier nur mal vor- und zur Diskussion stellen.

Weiterlesen…