Что такое Java 7 try-with-resources эквивалентно байт-коду с использованием try-catch-finally? - PullRequest
20 голосов
/ 22 октября 2011

Я пытаюсь понять, как работает новый оператор try-with-resources , воссоздав его с помощью регулярных операторов try-catch-finally. Учитывая следующий тестовый класс с использованием 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();
        }
    }
}

Ответы [ 2 ]

26 голосов
/ 22 октября 2011

Для класса 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, таблицы байт-кода и исключений для основного метода вклассы TryWithResources и TryCatchFinally:

  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

Для класса 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();
        }
    }
}

Байт-код и таблицы исключений для метода main в классах TryWithResources2 и TryCatchFinally2:

  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
23 голосов
/ 22 октября 2011

В соответствии с разделом 14.20.3.1 Спецификации языка Java (JLS) для Java 7:

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 более подробно... слишком много, чтобы воспроизвести здесь.


Глава Java 7 JLS по использованию ресурсов доступна в формате HTML здесь , и вы можете получить PDF-версиюJLS здесь .

...