什么是Java 7 try-with-resources字节码等效使用try-catch-finally?

我试图通过使用常规的try-catch-finally语句重新创建它来了解新的try-with-resources语句是如何工作的。 给定以下使用Java 7 try-with-resources的测试类:

import java.io.IOException; import java.util.zip.GZIPOutputStream; public class TryWithResources { public static void main(String[] args) { try (GZIPOutputStream gzip = new GZIPOutputStream(System.out)) { gzip.write("TEST".getBytes("UTF-8")); } catch (IOException ioe) { ioe.printStackTrace(); } } } 

你会如何重写这个类来使用try-catch-finally语句,它产生与try-with-resources语句产生完全相同的字节码? 此外,使用两个资源时的问题相同,如下例所示:

 import java.io.ByteArrayOutputStream; import java.io.IOException; import java.util.zip.GZIPOutputStream; public class TryWithResources2 { public static void main(String[] args) { try (ByteArrayOutputStream baos = new ByteArrayOutputStream(); GZIPOutputStream gzip = new GZIPOutputStream(baos)) { gzip.write("TEST".getBytes("UTF-8")); } catch (IOException ioe) { ioe.printStackTrace(); } } } 

对于TryWithResources类,以下类生成与try-with-resources相同的字节码:

 import java.io.IOException; import java.util.zip.GZIPOutputStream; public class TryCatchFinally { public static void main(String[] args) { try { final GZIPOutputStream gzip = new GZIPOutputStream(System.out); Throwable gzipEx = null; try { gzip.write("TEST".getBytes("UTF-8")); } catch (Throwable t) { gzipEx = t; throw t; } finally { if (gzip != null) { if (gzipEx != null) { try { gzip.close(); } catch (Throwable t) { gzipEx.addSuppressed(t); } } else { gzip.close(); } } } } catch (IOException ioe) { ioe.printStackTrace(); } } } 

使用Sun JDK 1.7.0, TryWithResourcesTryCatchFinally类中main方法的字节码和exception表是:

  stack=3, locals=6, args_size=1 0: new #2 // class java/util/zip/GZIPOutputStream 3: dup 4: getstatic #3 // Field java/lang/System.out:Ljava/io/PrintStream; 7: invokespecial #4 // Method java/util/zip/GZIPOutputStream."":(Ljava/io/OutputStream;)V 10: astore_1 11: aconst_null 12: astore_2 13: aload_1 14: ldc #5 // String TEST 16: ldc #6 // String UTF-8 18: invokevirtual #7 // Method java/lang/String.getBytes:(Ljava/lang/String;)[B 21: invokevirtual #8 // Method java/util/zip/GZIPOutputStream.write:([B)V 24: aload_1 25: ifnull 95 28: aload_2 29: ifnull 48 32: aload_1 33: invokevirtual #9 // Method java/util/zip/GZIPOutputStream.close:()V 36: goto 95 39: astore_3 40: aload_2 41: aload_3 42: invokevirtual #11 // Method java/lang/Throwable.addSuppressed:(Ljava/lang/Throwable;)V 45: goto 95 48: aload_1 49: invokevirtual #9 // Method java/util/zip/GZIPOutputStream.close:()V 52: goto 95 55: astore_3 56: aload_3 57: astore_2 58: aload_3 59: athrow 60: astore 4 62: aload_1 63: ifnull 92 66: aload_2 67: ifnull 88 70: aload_1 71: invokevirtual #9 // Method java/util/zip/GZIPOutputStream.close:()V 74: goto 92 77: astore 5 79: aload_2 80: aload 5 82: invokevirtual #11 // Method java/lang/Throwable.addSuppressed:(Ljava/lang/Throwable;)V 85: goto 92 88: aload_1 89: invokevirtual #9 // Method java/util/zip/GZIPOutputStream.close:()V 92: aload 4 94: athrow 95: goto 103 98: astore_1 99: aload_1 100: invokevirtual #13 // Method java/io/IOException.printStackTrace:()V 103: return Exception table: from to target type 32 36 39 Class java/lang/Throwable 13 24 55 Class java/lang/Throwable 13 24 60 any 70 74 77 Class java/lang/Throwable 55 62 60 any 0 95 98 Class java/io/IOException 

对于TryWithResources2类,以下类生成与try-with-resources相同的字节码:

 import java.io.ByteArrayOutputStream; import java.io.IOException; import java.util.zip.GZIPOutputStream; public class TryCatchFinally2 { public static void main(String[] args) { try { final ByteArrayOutputStream baos = new ByteArrayOutputStream(); Throwable baosEx = null; try { final GZIPOutputStream gzip = new GZIPOutputStream(baos); Throwable gzipEx = null; try { gzip.write("TEST".getBytes("UTF-8")); } catch (Throwable t) { gzipEx = t; throw t; } finally { if (gzip != null) { if (gzipEx != null) { try { gzip.close(); } catch (Throwable t) { gzipEx.addSuppressed(t); } } else { gzip.close(); } } } } catch (Throwable t) { baosEx = t; throw t; } finally { if (baos != null) { if (baosEx != null) { try { baos.close(); } catch (Throwable t) { baosEx.addSuppressed(t); } } else { baos.close(); } } } } catch (IOException ioe) { ioe.printStackTrace(); } } } 

TryWithResources2TryCatchFinally2类中main方法的字节码和exception表是:

  stack=3, locals=10, args_size=1 0: new #2 // class java/io/ByteArrayOutputStream 3: dup 4: invokespecial #3 // Method java/io/ByteArrayOutputStream."":()V 7: astore_1 8: aconst_null 9: astore_2 10: new #4 // class java/util/zip/GZIPOutputStream 13: dup 14: aload_1 15: invokespecial #5 // Method java/util/zip/GZIPOutputStream."":(Ljava/io/OutputStream;)V 18: astore_3 19: aconst_null 20: astore 4 22: aload_3 23: ldc #6 // String TEST 25: ldc #7 // String UTF-8 27: invokevirtual #8 // Method java/lang/String.getBytes:(Ljava/lang/String;)[B 30: invokevirtual #9 // Method java/util/zip/GZIPOutputStream.write:([B)V 33: aload_3 34: ifnull 114 37: aload 4 39: ifnull 61 42: aload_3 43: invokevirtual #10 // Method java/util/zip/GZIPOutputStream.close:()V 46: goto 114 49: astore 5 51: aload 4 53: aload 5 55: invokevirtual #12 // Method java/lang/Throwable.addSuppressed:(Ljava/lang/Throwable;)V 58: goto 114 61: aload_3 62: invokevirtual #10 // Method java/util/zip/GZIPOutputStream.close:()V 65: goto 114 68: astore 5 70: aload 5 72: astore 4 74: aload 5 76: athrow 77: astore 6 79: aload_3 80: ifnull 111 83: aload 4 85: ifnull 107 88: aload_3 89: invokevirtual #10 // Method java/util/zip/GZIPOutputStream.close:()V 92: goto 111 95: astore 7 97: aload 4 99: aload 7 101: invokevirtual #12 // Method java/lang/Throwable.addSuppressed:(Ljava/lang/Throwable;)V 104: goto 111 107: aload_3 108: invokevirtual #10 // Method java/util/zip/GZIPOutputStream.close:()V 111: aload 6 113: athrow 114: aload_1 115: ifnull 185 118: aload_2 119: ifnull 138 122: aload_1 123: invokevirtual #13 // Method java/io/ByteArrayOutputStream.close:()V 126: goto 185 129: astore_3 130: aload_2 131: aload_3 132: invokevirtual #12 // Method java/lang/Throwable.addSuppressed:(Ljava/lang/Throwable;)V 135: goto 185 138: aload_1 139: invokevirtual #13 // Method java/io/ByteArrayOutputStream.close:()V 142: goto 185 145: astore_3 146: aload_3 147: astore_2 148: aload_3 149: athrow 150: astore 8 152: aload_1 153: ifnull 182 156: aload_2 157: ifnull 178 160: aload_1 161: invokevirtual #13 // Method java/io/ByteArrayOutputStream.close:()V 164: goto 182 167: astore 9 169: aload_2 170: aload 9 172: invokevirtual #12 // Method java/lang/Throwable.addSuppressed:(Ljava/lang/Throwable;)V 175: goto 182 178: aload_1 179: invokevirtual #13 // Method java/io/ByteArrayOutputStream.close:()V 182: aload 8 184: athrow 185: goto 193 188: astore_1 189: aload_1 190: invokevirtual #15 // Method java/io/IOException.printStackTrace:()V 193: return Exception table: from to target type 42 46 49 Class java/lang/Throwable 22 33 68 Class java/lang/Throwable 22 33 77 any 88 92 95 Class java/lang/Throwable 68 79 77 any 122 126 129 Class java/lang/Throwable 10 114 145 Class java/lang/Throwable 10 114 150 any 160 164 167 Class java/lang/Throwable 145 152 150 any 0 185 188 Class java/io/IOException 

根据Java 7的Java语言规范(JLS)第14.20.3.1节:

 try (VariableModifiersopt R Identifier = Expression ...) Block 

相当于

 { final VariableModifiers_minus_final R Identifier = Expression; Throwable #primaryExc = null; try ResourceSpecification_tail Block catch (Throwable #t) { #primaryExc = #t; throw #t; } finally { if (Identifier != null) { if (#primaryExc != null) { try { Identifier.close(); } catch (Throwable #suppressedExc) { #primaryExc.addSuppressed(#suppressedExc); } } else { Identifier.close(); } } } } 

JLS涉及更多细节……在这里重现太多了。


有关try-with-resources的Java 7 JLS章节在此处以HTML格式提供,您可以在此处获取JLS的PDF版本。