Java 编译时检查异常。finally块隐式抛出未检查异常的情况

Java 编译时检查异常。finally块隐式抛出未检查异常的情况,java,exception-handling,compile-time,try-catch-finally,unchecked-exception,Java,Exception Handling,Compile Time,Try Catch Finally,Unchecked Exception,下面的代码编译得非常完美。我相信这是因为编译器在编译时知道控件将转到finally块并抛出未检查的异常(这是可以的,不需要处理),并且它知道在此之前代码抛出的所有其他异常都将丢失。所以不必为他们担心 try{ // DoSomething(); }catch(Exception e){ // Throw checked exception }finally{ // Throw unchecked exception } 例如: public class TestC

下面的代码编译得非常完美。我相信这是因为编译器在编译时知道控件将转到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();
    }
}
}
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();
}
}
到目前为止还不错,直到我从一个方法抛出未检查的异常为止。

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) {
        throw new FileNotFoundException(); 
    } finally {
        throw new NullPointerException();
    }
}
}
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块将抛出最后一个异常(未选中),并且不需要担心catch块中的异常,即使它是未处理的选中异常,因为它们无论如何都会丢失!知道m2()被声明为专门引发未检查的异常(RuntimeException)

有人能更好地解释第二段代码中为什么会出现编译错误吗? 谢谢:)

例外情况不会自行“抛出”。您必须显式地处理被调用方法引发的任何已检查异常——无论它们发生在何处。任何抛出选中异常的调用都必须被try-catch块包围,或者调用子方法的方法必须声明抛出相同类型的异常。这不适用于选中的异常

这意味着,你已经

catch (Exception e) {
     c.m1(); 
         // or just throw it here
         // throw new FileNotFoundException();
}
您必须捕获由
m1
引发的选中异常,因为
main
没有声明它会引发任何异常

对于try/catch上的
finally
块,您仍然必须处理被调用方法抛出的任何已检查异常——即使在catch块中也是如此。但是,如果您显式地抛出检查过的异常,并使用一个finally块显式地抛出运行时异常,编译器会允许它,因为它肯定知道事件序列是什么——在任何情况下,在任何时间

异常不会“抛出”它们自己。您必须显式地处理被调用方法引发的任何已检查异常——无论它们发生在何处。任何抛出选中异常的调用都必须被try-catch块包围,或者调用子方法的方法必须声明抛出相同类型的异常。这不适用于选中的异常

这意味着,你已经

catch (Exception e) {
     c.m1(); 
         // or just throw it here
         // throw new FileNotFoundException();
}
您必须捕获由
m1
引发的选中异常,因为
main
没有声明它会引发任何异常


对于try/catch上的
finally
块,您仍然必须处理被调用方法抛出的任何已检查异常——即使在catch块中也是如此。但是,如果您显式地抛出检查过的异常,并使用一个finally块显式地抛出运行时异常,编译器会允许它,因为它肯定知道事件序列是什么——在任何情况下,在任何时间

编译器不能处理这种情况。你能说一下为什么你会用这种方式写代码吗?我实际上没有写任何代码。我只是在学习一些关于检查和未检查异常的基础知识,以及编译器如何操作和检查异常。我考虑过这种情况,我想问问有没有人知道。我会试着去想一个真实的例子,但是正如你说的,编译器似乎无论如何都不会处理这样的情况,编译器不会处理这样的情况。你能说一下为什么你会用这种方式写代码吗?我实际上没有写任何代码。我只是在学习一些关于检查和未检查异常的基础知识,以及编译器如何操作和检查异常。我考虑过这种情况,我想问问有没有人知道。我将尝试思考一个真实的示例,但正如您所说,编译器似乎无论如何都不会处理这种情况。但是,如果您捕获(异常e){c.m1();}最后{抛出新的NullPointerException();},它会编译得很好。这是因为编译器可以看到肯定会发生运行时异常。即使另一个类说它抛出了一个,这可能会改变,这将改变最终块的决定。对!您让我认为编译器不知道c.m2()是TestClass bcz中的实际m2(),有可能在运行时“c”将指向扩展TestClass的另一个对象,该对象重写m2(),而其声明中没有throws子句(这是有效且可能的)。现在完全可以理解了,但是我将m2()定义为静态final(以确保告诉编译器m2()在运行时不可能更改),但仍然会得到相同的错误。我想Java忽略了这一点。也许他们会在以后的verison中增强编译器的检入功能。但是如果您捕获(异常e){c.m1();}最后{抛出新的NullPointerException();}它会编译得很好,这是因为编译器可以确定会发生运行时异常。即使另一个类说它抛出了一个,这可能会改变,这将改变最终块的决定。对!您让我认为编译器不知道c.m2()是TestClass bcz中的实际m2(),有可能在运行时“c”将指向扩展TestClass的另一个对象,该对象重写m2(),而其声明中没有throws子句(这是有效且可能的)。现在完全可以理解了,但是我将m2()定义为静态final(以确保告诉编译器m2()在运行时不可能更改),但仍然会得到相同的错误。我想Java忽略了这一点。也许他们会在稍后的verison中增强编译器签入。