23 Stimmen

Was ist das Java 7 try-with-resources Bytecode-Äquivalent mit try-catch-finally?

Ich versuche zu verstehen, wie die neue Versuch-mit-Ressourcen-Anweisung funktioniert, indem es mit regulären try-catch-finally-Anweisungen neu erstellt wird. Gegeben sei die folgende Testklasse mit 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();
        }
    }
}

Wie würden Sie diese Klasse umschreiben, um try-catch-finally-Anweisungen zu verwenden, die genau denselben Bytecode erzeugen wie die try-with-resources-Anweisung? Dieselbe Frage stellt sich auch, wenn zwei Ressourcen verwendet werden, wie im folgenden Beispiel:

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();
        }
    }
}

30voto

Dan Cruz Punkte 14704

Für die TryWithResources Klasse erzeugt die folgende Klasse gleichwertigen Bytecode wie die Klasse 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();
        }
    }
}

Bei Verwendung von Sun JDK 1.7.0 werden der Bytecode und die Ausnahmetabellen für die Hauptmethode in beiden TryWithResources y TryCatchFinally Klassen ist:

  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."<init>":(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

Für die TryWithResources2 Klasse erzeugt die folgende Klasse gleichwertigen Bytecode wie die Klasse 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();
        }
    }
}

Der Bytecode und die Ausnahmetabellen für die Hauptmethode in beiden TryWithResources2 y TryCatchFinally2 Klassen ist:

  stack=3, locals=10, args_size=1
     0: new           #2                  // class java/io/ByteArrayOutputStream
     3: dup           
     4: invokespecial #3                  // Method java/io/ByteArrayOutputStream."<init>":()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."<init>":(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

25voto

Stephen C Punkte 665668

Gemäß Abschnitt 14.20.3.1 der Java Language Specification (JLS) für Java 7:

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

ist gleichbedeutend mit

{
    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();
            }
        }
    }
}

Die JLS geht viel mehr ins Detail ... zu viel, um es hier wiederzugeben.


Das Java 7 JLS-Kapitel über Try-with-Resources ist in HTML-Form verfügbar ici und Sie können die PDF-Version der JLS erhalten ici .

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X