© Rawpixel.com/Shutterstock.com
„try-with-resource” in Plain Java

Wo der Unterschied liegt


Vor ein paar Monaten hat ein Teilnehmer unseres Kurses „Refactoring to Java 8 Streams“ diese Frage gestellt: Warum fügt „try-with-resource“ keine unterdrückte „NullPointerException“ hinzu, wenn die in „try()“ deklarierte Ressource null ist? Eine interessante Frage. Als ich nach einer Antwort gesucht habe, ist mir etwas klar geworden.

Ich hatte nicht wirklich eine Ahnung, wie der Java-Code aussähe, wenn ich ihn nicht mit try-with-resource aufhübschte. Ich habe mich mit javap -c durchgeboxt, bis meine manuelle und die automatische Version gleich waren.

Fangen wir mit der try-with-resource-Version an:

try (InputStream io = getNullStream()) { FileInputStream fi = new FileInputStream("somefile.bin"); io.available(); } 

Die Methode getNullStream() liefert null zurück. somefile.bin existiert nicht. Entsprechend habe ich mit einer FileNotFoundException mit einer unterdrückten NullPointerException gerechnet. Ich habe gedacht, der generierte Bytecode sei äquivalent zu Listing 1.

Listing 1

InputStream io = getNullStream(); Throwable throwable = null; try { FileInputStream fi = new FileInputStream("somefile.bin"); io.available(); } catch (Throwable t) { throwable = t; throw t; } finally { if (throwable == null) { io.close(); } else { try { io.close(); } catch (Throwable th) { // NullPointerException throwable.addSuppressed(th); } } }

Ich habe den Code nach oben und nach unten verschoben und einen Test eingebaut, ob io != null ist. Anschließend habe ich einen einfachen Java-Code gefunden, der dem Java-7-try-with-resource-Konstrukt entspricht. Allerdings sollten wir im Hinterkopf behalten, dass es einen Test gibt, io null ist, bevor wir versuchen, zu schließen (Listing 2).

Listing 2

InputStream io = getNullStream(); Throwable throwable = null; try { FileInputStream fi = new FileInputStream("somefile.bin"); io.available(); } catch (Throwable t) { throwable = t; throw t; } finally { if (io != null) { if (throwable != null) { try { io.close(); } catch (Throwable t) { throwable.addSuppressed(t); } } else { io.close(); } } }

Listing 3 zeigt den via java -c zerlegten Bytecode. Der generierte Code sieht in Java 7, 8, 9 und 10 identisch aus.

Listing 3

 0: invokestatic #4 // getNullStream:InputStream; 3: astore_0 4: aconst_null 5: astore_1 6: new #5 // class java/io/FileInputStream 9: dup 10: ldc #6 // String somefile.bin 12: invokespecial #7 // FileInputStream."<init>"(String) 15: astore_2 16: aload_0 17: invokevirtual #8 // InputStream.available() 20: pop 21: aload_0 22...

Neugierig geworden?

Angebote für Teams

Für Firmen haben wir individuelle Teamlizenzen. Wir erstellen Ihnen gerne ein passendes Angebot.

Das Library-Modell:
IP-Zugang

Das Company-Modell:
Domain-Zugang