当前位置: 首页 > 知识库问答 >
问题:

Java用编译器实现资源尝试

淳于功
2023-03-14

我想知道,当异常发生时,try with resource语句如何在进入catch块之前关闭资源。当异常发生时,执行立即跳转到catch块。因此,try-with-resource实际上关闭了资源。

为了更好地理解它的工作原理,我决定看看编译器是如何实现它的。我编写了下面的代码并对其进行了编译。

public class Test
{
    public static void main(final String[] args) {
       //I used same JDK for compilation and execution.
        System.out.println("Java version: " + System.getProperty("java.version") + "\n");
        try(CloseMe me = new CloseMe(); 
                CloseMeToo meToo = new CloseMeToo()){
                
                System.out.println("trying");
                throw new Exception("try failed");

            } catch(Exception e) {
                System.out.println("failed");
                System.out.println("\n");
                System.out.println(e.getMessage());
                System.out.println(e.getSuppressed()[0].getMessage());
                System.out.println(e.getSuppressed()[1].getMessage());
            }
    }
}

class CloseMe implements AutoCloseable {
    @Override
    public void close() throws Exception {
        System.out.println("me closing!");
        throw new Exception("don't close me :o");
    }
}

class CloseMeToo implements AutoCloseable {
    @Override
    public void close() throws Exception {
        System.out.println("meToo closing!");
        throw new Exception("don't close me too :O");
    }
}

输出

Java version: 15.0.1

trying
meToo closing!
me closing!
failed


try failed
don't close me too :O
don't close me :o

然后我访问了www.javadecompilers.com,并在那里试用了反编译程序。两个反编译程序给出了不错的结果:CFR0.150和Fernflower。CFR是最可读性和完整的,所以张贴在这里。

public class Test
{
    public static void main(final String[] args) throws Throwable{
        System.out.println("Java version: " + System.getProperty("java.version") + "\n");
        
        try {
            Throwable throwable = null;
            Object var2_4 = null;     //<-- where this variable is used?
            try {
                CloseMe me = new CloseMe();
                try {
                    CloseMeToo meToo = new CloseMeToo();
                    try {
                        System.out.println("trying");
                        throw new Exception("try failed");
                    }
                    catch (Throwable throwable2) {
                        throwable = throwable2; //<-- I put this line to make it work
                        if (meToo != null) {
                            meToo.close();
                        }
                        throw throwable2;
                    }
                }
                catch (Throwable throwable3) {
                    if (throwable == null) {
                        throwable = throwable3;
                    } else if (throwable != throwable3) {
                        throwable.addSuppressed(throwable3);
                    }
                    if (me != null) {
                        me.close();
                    }
                    throw throwable;
                }
            }
            catch (Throwable throwable4) {
                if (throwable == null) {
                    throwable = throwable4;
                } else if (throwable != throwable4) {
                    throwable.addSuppressed(throwable4);
                }
                throw throwable;
            }
        }
        catch (Exception e) {
            System.out.println("failed");
            System.out.println("\n");
            System.out.println(e.getMessage());
            System.out.println(e.getSuppressed()[0].getMessage());
            System.out.println(e.getSuppressed()[1].getMessage());
        }
    }
}

我知道反编译器有局限性。理想的反编译器会给我同样的尝试资源,我不会看到这些细节。所以可以。
我的问题是:

  1. 在上述反编译代码中,变量var2_4未使用。此外,我还必须添加一行以使其像try-with-resource一样工作。我认为代码不完整。如果有,你能补充/解释缺少的部分吗?
  2. 如果任何一个懂字节码的人,把类文件翻译成精确的Java码,那就太好了。或者告诉我在哪里可以获得工具来完成这项工作。

谢谢!

共有1个答案

柳涵映
2023-03-14

在Java语言规范第14.20.3节中充分记录了使用资源进行尝试的行为。尝试使用资源。

具体表现为以下缩写版的问题代码:

try (CloseMe me = new CloseMe(); CloseMeToo meToo = new CloseMeToo()) {
    System.out.println("trying");
} catch (Exception e) {
    System.out.println("failed");
}

首先转换为:

try {
    try (CloseMe me = new CloseMe(); CloseMeToo meToo = new CloseMeToo()) {
        System.out.println("trying");
    }
} catch (Exception e) {
    System.out.println("failed");
}

然后向:

try {
    final CloseMe me = new CloseMe();
    Throwable #primaryExc1 = null;

    try (CloseMeToo meToo = new CloseMeToo()) {
        System.out.println("trying");
    } catch (Throwable #t) {
        #primaryExc1 = #t;
        throw #t;
    } finally {
        if (me != null) {
            if (#primaryExc1 != null) {
                try {
                    me.close();
                } catch (Throwable #suppressedExc) {
                    #primaryExc1.addSuppressed(#suppressedExc);
                }
            } else {
                me.close();
            }
        }
    }
} catch (Exception e) {
    System.out.println("failed");
}

然后向:

try {
    final CloseMe me = new CloseMe();
    Throwable #primaryExc1 = null;

    try {
        final CloseMeToo meToo = new CloseMeToo()
        Throwable #primaryExc2 = null;

        try {
            System.out.println("trying");
        catch (Throwable #t) {
            #primaryExc2 = #t;
            throw #t;
        } finally {
            if (meToo != null) {
                if (#primaryExc2 != null) {
                    try {
                        meToo.close();
                    } catch (Throwable #suppressedExc) {
                        #primaryExc2.addSuppressed(#suppressedExc);
                    }
                } else {
                    meToo.close();
                }
            }
        }
    } catch (Throwable #t) {
        #primaryExc1 = #t;
        throw #t;
    } finally {
        if (me != null) {
            if (#primaryExc1 != null) {
                try {
                    me.close();
                } catch (Throwable #suppressedExc) {
                    #primaryExc1.addSuppressed(#suppressedExc);
                }
            } else {
                me.close();
            }
        }
    }
} catch (Exception e) {
    System.out.println("failed");
}
 类似资料:
  • 我的系统中有以下配置: Apache Maven 3.5.2 Maven主页: /usr/share/mavenJava版本:1.8.0_162,供应商:Oracle CorporationJava主页: /usr/lib/jvm/java-8-openjdk-amd64/jre默认语言环境:en_US,平台编码:UTF-8操作系统名称:"linux",版本:"4.15.0-20-通用", arc

  • 我需要打开N个多播套接字(其中N来自参数列表的大小)。然后,我将向循环中的N个套接字中的每个套接字发送相同的数据,最后关闭每个套接字。我的问题是,如何使用try with resources块来实现这一点?以下是我将如何使用单个资源来实现这一点: 我能想到的使用多个端口执行此操作的唯一方法如下: 有没有一种更简洁的方法来实现这一点,或者我提出的解决方案是否尽可能好?

  • 问题内容: 我正在为Pascal的子集编写编译器。编译器为一台组装好的机器生成机器指令。我想为此机器语言编写一个窥孔优化器,但是我无法替换一些更复杂的模式。 窥孔优化器规格 我研究了几种编写窥孔优化器的方法,并且选择了后端方法: 每当要生成机器指令时,编码器都会调用函数。 检查猫眼优化表: 如果当前指令与模式的尾部匹配: 检查先前发出的说明是否匹配 如果所有指令都与该模式匹配,则应用优化,修改代码

  • 问题内容: 我一直在看代码,并且看到了尝试资源的机会。我以前使用过标准的try-catch语句,看起来它们在做同样的事情。所以我的问题是“ 尝试使用资源”与“尝试捕获 ”之间的区别是什么,哪个更好。 这是尝试使用资源: 问题答案: 尝试使用资源的重点是确保可靠地关闭资源。 当你不使用try-with-resources时,存在一个潜在的陷阱,称为异常屏蔽。当try块中的代码引发异常,而finall

  • 无法从com提取资源。AndroidAAPT编译器。ParsedResource@636e1e76. 任务“:app:mergeDebugResources”的执行失败。 执行com.android.build.gradle.internal.res.时发生故障ResourceCompilerRunnable资源编译失败(未能编译值资源文件E:\My Client\Henkako\HenkakoP

  • 问题内容: 我是的新手,我想知道对于资源来说,我是否必须为每个添加一个,否则它将与上面的代码一起使用 问题答案: 通过在 块中声明所有资源,可以尝试将资源与多个资源一起使用,并且此功能是 Java 7中 引入的,而不是 Java 8中 引入的。如果有多个资源,则可以如下所示 在此示例中,该语句包含两个用分号分隔的声明: ZipFile 和 BufferedWriter 。当它紧随其后的代码块终止时