返回尝试使用资源。它是JVM的正确行为吗?

时间:2016-09-20 13:40:52

标签: java jvm specifications try-with-resources

在下面的代码示例中,我希望将1作为方法testM()的返回值。但是由于TestAutoCloseable.close()方法中的异常,我得到了意想不到的行为。

我的问题是:“这是JVM的正常行为吗?”

public static void main(String[] args) {
    ProgrammerTwo programmerTwo = new ProgrammerTwo();
    System.out.println(programmerTwo.testM());
}

int testM() {
    try (TestAutoCloseable closable = new TestAutoCloseable()) {
        System.out.println("Do first return");
        return 1;
    } catch (IOException e) {
        System.out.println("handled");
    }
    System.out.println("Do something, that shouldn't do if first return have happened");
    return 2;
}

static class TestAutoCloseable implements AutoCloseable {

    @Override
    public void close() throws IOException {
        throw new IOException();
    }
}

因为如果它是正常行为,我们不应该在try with resource语句中使用return或break语句。它应该是反模式的。

2 个答案:

答案 0 :(得分:1)

try-with-resources语句如何工作的详细信息位于JLS的this section中。在您的情况下,它是扩展 try-with-resources,因为它具有下面引用中定义的catch子句(请注意最后突出显示的语句)。

  

带有至少一个catch子句和/或finally子句的try-with-resources语句称为扩展的try-with-resources语句。

     

扩展的try-with-resources语句的含义:

try ResourceSpecification
     Block
[Catches]
[Finally]
     

通过以下转换给出嵌套在try-catch或try-finally或try-catch-finally语句中的基本try-with-resources语句:

try {
  try ResourceSpecification          <--- exception thrown in this basic try-with-resources
      Block
}
[Catches]
[Finally]
  

翻译的效果是将资源规范放在try语句的“内部”。 这允许扩展的try-with-resources语句的catch子句捕获由于自动初始化或关闭任何资源而导致的异常。

这意味着关闭资源会在外部try块的主体内发生,导致在catch块中抛出并处理异常,并控制恢复扩展try-with-resources语句之后的语句。

实际上,整个方法testM等同于:

int testM() {
    try {
       final TestAutoCloseable closable = new TestAutoCloseable();
       Throwable #primaryExc = null;
       try {
           System.out.println("Do first return");
           return 1;
       } catch (Throwable #t) {
           #primaryExc = #t;
           throw #t;
       } finally {
           if (closable != null) {
              if (#primaryExc != null) {
                 try {
                    closable.close();
                 } catch (Throwable #suppressedExc) {
                    #primaryExc.addSuppressed(#suppressedExc);
                 }
              } else {
                 closable.close();
              }
          }
       }
    } catch (IOException e) {
       System.out.println("handled");
    }
    System.out.println("Do something, that shouldn't do if first return have happened");
    return 2;
}

答案 1 :(得分:0)

简单来说,当你的try-with-resource块退出时,抛出一个IOException(因为你从 close()抛出它,所以值 1 从来没有从方法返回,而是JVM移动到catch块,因为根据规则,一旦发生任何异常,try块中的所有重新映射代码都不会被执行而JVM移动到catch块。所以现在你的catch块运行,然后执行剩余的代码