【问题标题】:Compile-Time Checking of Exceptions. Case where finally block is throwing unchecked exception implicitly异常的编译时检查。 finally 块隐式抛出未经检查的异常的情况
【发布时间】:2023-03-20 02:11:01
【问题描述】:

以下代码完美编译。我相信这是因为编译器在编译时知道控件将转到 finally 块并抛出未经检查的异常(这没关系,不需要处理)并且它知道代码之前抛出的所有其他异常至此都迷失了。所以不用担心他们。

try{
     // DoSomething();
}catch(Exception e){ 
     // Throw checked exception
}finally{
    // Throw unchecked exception
}

示例:

public class TestClass {
public static void main(String[] args) {
    TestClass c = new TestClass();
    try {
        // Whatever
    } catch (Exception e) {
        throw new FileNotFoundException(); 
    } finally {
        throw new NullPointerException();
    }
}
}

到目前为止一切顺利,直到我从方法中抛出未经检查的异常。

try{
     // DoSomething();
}catch(Exception e){ 
     // Call a method that throws a checked exception
     // or just throw the checked exception from here

}Finally{
    // Call a method that throw an unchecked exception
}

示例:

public class TestClass {
public static void main(String[] args) {
    TestClass c = new TestClass();
    try {
        //Whatever
    } catch (Exception e) {
         c.m1(); 
             // or just throw it here
             // throw new FileNotFoundException();
    } finally {
        c.m2();
    }
}

public void m1() throws IOException {
    throw new FileNotFoundException();
}

public void m2() throws RuntimeException {
    throw new NullPointerException();
}
}

此代码将无法编译。它将 c.m1() 标记为错误“未处理的异常类型 _”(eclipse)或“未报告的异常 _;必须捕获或声明为抛出”(cmd)。

就像它忽略了 finally 块将抛出 LAST 异常(未检查),即使它是未处理的检查异常,也无需担心 catch 块中的异常,因为它们无论如何都会丢失!知道 m2() 被声明为专门抛出未经检查的异常 (RuntimeException)。

有没有人更好地解释为什么第二个代码中存在编译错误? 谢谢:)

【问题讨论】:

  • 编译器无法处理这种情况。你能说说为什么你会这样写代码吗?
  • 我实际上并没有编写任何代码。我只是在学习一些关于已检查和未检查异常的基础知识,以及编译器如何表现和检查异常。我想到了这种情况,我想问问有人有什么想法。我会试着想一个真实的例子,但正如你所说,编译器似乎无论如何都不会处理这种情况。

标签: java exception-handling compile-time try-catch-finally unchecked-exception


【解决方案1】:

异常只是不会“抛出”自己。您必须明确处理被调用方法抛出的任何检查异常——无论它们发生在哪里。你调用的任何抛出检查异常的东西都必须被一个 try catch 块包围,或者调用子方法的方法必须声明抛出相同类型的异常。这不适用于已检查的异常。

这意味着,你拥有的地方

catch (Exception e) {
     c.m1(); 
         // or just throw it here
         // throw new FileNotFoundException();
}

您必须捕获m1 抛出的已检查异常,因为main 没有声明它抛出任何东西。

使用 try/catch 上的 finally 块,您仍然必须处理被调用方法抛出的任何检查异常——即使在 catch 块中也是如此。但是,在您使用明确抛出运行时异常的 finally 块显式抛出已检查异常的情况下,编译器允许这样做,因为它可以确定事件的顺序是什么——在任何情况下都可以。

【讨论】:

  • 但如果你执行 catch(Exception e){c.m1();}finally{throw new NullPointerException();},它编译得很好
  • 那是因为编译器可以看到肯定会发生运行时异常。即使其他类说它抛出一个,这也可能会改变,这将改变 finally 块的决定。
  • 对!你让我认为编译器不知道 c.m2() 是 TestClass bcz 中的实际 m2() 有可能在运行时“c”将指向扩展 TestClass 并覆盖 m2( ) 在其声明中没有 throws 子句(这是有效且可能的)。现在完全有道理,但是我将 m2() 定义为 static final (以确保告诉编译器 m2() 不可能在运行时更改)但我仍然遇到相同的错误。我猜Java忽略了这一点。也许他们会在以后的版本中增强编译器检查。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-12-04
  • 1970-01-01
  • 1970-01-01
  • 2016-07-21
相关资源
最近更新 更多