为啥即使永远不会抛出 IOException 也可以在 java 7 中捕获 IOException

Posted

技术标签:

【中文标题】为啥即使永远不会抛出 IOException 也可以在 java 7 中捕获 IOException【英文标题】:Why it is okay in java 7 to catch an IOException even if IOException will never be thrown为什么即使永远不会抛出 IOException 也可以在 java 7 中捕获 IOException 【发布时间】:2014-12-21 02:34:20 【问题描述】:
public class SampleCloseable implements AutoCloseable 

    private String name;

    public SampleCloseable(String name)
        this.name = name;
    

    @Override
    public void close() throws Exception 
        System.out.println("closing: " + this.name);
    

和主类

public class Main

    public static void main(String args[]) 
      try(SampleCloseable sampleCloseable = new SampleCloseable("test1"))

          System.out.println("im in a try block");

       catch (IOException  e) 
          System.out.println("IOException is never thrown");

       catch (Exception e) 

       finally
          System.out.println("finally");
      

    

但是当我在 SampleCloseable 中的 close() 方法上删除 throws 异常时 我收到一个编译器错误,说 IOException 永远不会在相应的 try 块中抛出。

【问题讨论】:

为什么不应该呢?你是老板。你决定做什么,即使它是愚蠢的。 IOException 扩展异常 编译器不知道永远不会抛出 IOException。你也没有。 【参考方案1】:

因为你抛出了一个通用的异常。由于 IOException 继承自 Exception,因此它可能被 close() 方法抛出。调用者不知道它实际上并没有被抛出。它只看到表明它可以的方法签名。

事实上,close() 方法可以随意抛出任何类型的异常。当然这是不好的做法,您应该指定要抛出的特定异常。

【讨论】:

【参考方案2】:

您的困惑可能是,在 Java 7 中,[声明为]从 close 方法抛出的异常被抛出 inside try 块,所以你的 catch 块有抓住它。

您的close 方法被声明为抛出一个异常,因此您的catch 块必须捕获它,或者该方法必须被声明为抛出Exception

由于IOExceptionException 的子类,当然你也可以尝试捕捉它,只要你自己也捕捉/声明Exception

见JLS 14.20.3.2:

给出了扩展的 try-with-resources 语句 [...] 的含义 通过以下翻译为基本的 try-with-resources 语句 (§14.20.3.1) 嵌套在 try-catch 或 try-finally 或 try-catch-finally 语句。

您的代码被有效地翻译成以下内容。虽然有点冗长,但从下面的代码中应该可以清楚地看到代码中发生了什么。

public static void main(String args[]) 
  try 
      Throwable primaryEx = null ;
      SampleCloseable sampleCloseable = new SampleCloseable("test1")
      try 
          System.out.println("im in a try block");
       catch (Throwable t) 
          primaryEx = t;
          throw t;
       finally 
        if (sampleCloseable != null) 
        if (primaryEx != null) 
            try 
                sampleCloseable.close();
             catch (Throwable suppressedExc) 
                primaryEx.addSuppressed(suppressedExc);
            
         else 
            sampleCloseable.close();
        
      
   catch (IOException  e) 
      System.out.println("IOException is never thrown");

   catch (Exception e) 

   finally
      System.out.println("finally");
  

【讨论】:

以上是关于为啥即使永远不会抛出 IOException 也可以在 java 7 中捕获 IOException的主要内容,如果未能解决你的问题,请参考以下文章

为啥即使使用了调用,组合框也会抛出异常

对象扩展语法永远不会抛出错误吗?

为啥即使我 .catch() Promise.all() 也会抛出异常?

为啥即使元素存在,硒也会抛出未找到元素的错误? [复制]

在这种情况下永远不会抛出这个 AssertionError 吗?

为啥即使配置文件设置为分发,xcode 也会抛出此错误?