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

发布于 2024-12-11 21:34:01 字数 1222 浏览 0 评论 0原文

我试图了解新的 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();
        }
    }
}

I'm trying to understand how the new try-with-resources statement works by recreating it using regular try-catch-finally statements. Given the following test class using 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();
        }
    }
}

How would you rewrite this class to use try-catch-finally statements which produces exactly the same bytecode as the try-with-resources statement produces? Also, same question when two resources are used, as in the following example:

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

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

花落人断肠 2024-12-18 21:34:01

对于 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 中的 main 方法的字节码和异常表code> 和 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();
        }
    }
}

TryWithResources2TryCatchFinally2 类中 main 方法的字节码和异常表为:

  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

For the TryWithResources class, the following class produces equivalent bytecode as the 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();
        }
    }
}

Using Sun JDK 1.7.0, the bytecode and exception tables for the main method in both TryWithResources and TryCatchFinally classes is:

  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

For the TryWithResources2 class, the following class produces equivalent bytecode as the 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();
        }
    }
}

The bytecode and exception tables for the main method in both TryWithResources2 and TryCatchFinally2 classes is:

  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
坏尐絯℡ 2024-12-18 21:34:01

根据 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 此处

According to section 14.20.3.1 of the Java Language Specification (JLS) for Java 7:

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

is equivalent to

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

The JLS goes into a lot more detail ... too much to reproduce here.


The Java 7 JLS chapter on try-with-resources is available in HTML form here, and you can get the PDF version of the JLS here.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文