© Rawpixel.com/Shutterstock.com
Java Magazin
„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.

Heinz Kabutz


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 1InputStream 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 2InputStream 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: dup10: ldc #6 // String somefile.bin12: invokespecial #7 // FileInputStream.""(String)15: astore_216: aload_017: invokevirtual #8 // InputStream.available()20: pop21: aload_022: ifnull 9025: aload_126: ifnull 4529: aload_030: invokevirtual #9 // InputStream.close()33: goto 9036: astore_237: aload_138: aload_239: invokevirtual #11 // Throwable.addSuppressed(Throwable)42: goto 9045: aload_046: inv...

Java Magazin
„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.

Heinz Kabutz


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 1InputStream 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 2InputStream 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: dup10: ldc #6 // String somefile.bin12: invokespecial #7 // FileInputStream.""(String)15: astore_216: aload_017: invokevirtual #8 // InputStream.available()20: pop21: aload_022: ifnull 9025: aload_126: ifnull 4529: aload_030: invokevirtual #9 // InputStream.close()33: goto 9036: astore_237: aload_138: aload_239: invokevirtual #11 // Throwable.addSuppressed(Throwable)42: goto 9045: aload_046: inv...

Neugierig geworden?


   
Loading...

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