编译器未在已检查的异常上显示任何错误

时间:2017-03-02 08:38:17

标签: java exception core

我正在处理已检查的异常,并且在两者之间发现编译器没有在已检查的异常上显示任何错误并且工作正常的情况。

import java.io.FileNotFoundException;

interface A {
    void f() throws FileNotFoundException;
}

interface B {
    void f() throws InterruptedException;
}

interface C extends A, B {
}

public class Test implements C {
    public void f() {
        System.out.println("Hello world");
    }

    public static void main(String[] args) {
        C obj = new Test();
        obj.f(); // Working fine and printing "Hello World"
    }
}

请让我知道原因,我搜索了很多但没找到任何东西。

3 个答案:

答案 0 :(得分:2)

在面向对象的术语中,当您编程到接口(即实现接口或扩展接口)时,您不能比接口更具限制性。但是,您可以减少限制。因此,在您的示例中,接口的方法可能会也可能不会抛出FileNotFoundException和/或InterruptedException,但您的实现方法不会抛出异常。请注意,如果您的实现的方法抛出FileNotFoundException和/或InterruptedException,则它完全没问题,但如果它抛出其他一些异常,则不允许这样做。这意味着您的实现可能与接口相同或更少限制,但它不能更具限制性。

另请注意,当某人通过扩展接口类型(C)的变量或类'type(Test)的变量使用方法f()时,他们不需要处理异常。但是,如果他们通过接口类型A或B的变量使用方法f(),则需要处理异常。

A obj = new Test(); 
obj.f(); // need to handle FileNotFoundException

B obj = new Test();
obj.f(); // need to handle InterruptedException

C obj = new Test(); 
obj.f(); // don't need to handle any of the exceptions

Test obj = new Test(); 
obj.f(); // don't need to handle any of the exceptions

更多说明: C.f()不抛出异常的原因是它的父接口抛出了不同的异常。因此,根据参数“接口的实现或扩展不能更具限制性但可以限制更少”,C.f()限制较少的唯一方法是不抛出异常。否则,它将比至少其中一个父接口更具限制性。 另一方面,如果C的父母都抛出相同的异常,那么C.f()也需要抛出这些异常。但是,实现仍然可以选择不抛出异常。

import java.io.FileNotFoundException;

interface A{
    void f() throws FileNotFoundException;
}

interface B {
    void f() throws FileNotFoundException;
}

interface C extends A, B {
}

public class Test implements C {
    public void f() {
        System.out.println("Hello world");
    }

    public static void main(String[] args) {
        C obj = new Test();
        obj.f(); // Compilation error, unhandled exception

        Test obj = new Test();
        obj.f(); // No error
    }
}

答案 1 :(得分:2)

这个问题已得到正确回答,但我想补充一些说明。在代码中提出了各种评论和答案

C obj = new Test();
obj.f();

您不需要处理任何已检查异常的原因是“因为实现不会抛出任何已检查的异常”。这不是问题。实施是Test.f()。但obj.f()正在调用C.f()。编译器在编译时查看实现。它正在查看C中的规范。

您可以通过编写

来演示相同的编译器行为
void doThing(C obj) {
    obj.f();
}

这可以在不编写实现C的类的情况下进行编译。

现在doThing不知道正在调用f实现,但它仍然知道它不会抛出任何已检查的异常,因为C.f()无法抛出A.f() B.f()未声明的已检查异常。 C.f()抛出的可能检查异常集是两个超接口抛出的已检查异常集的交集

答案 2 :(得分:0)

方法可以抛出的一组检查异常是指在所有适用的类型中声明要抛出的一组检查异常的交集,而不是联合[JLS 15.12.2.5]。 编译器仅检查方法声明中的异常。

interface InterfaceA{
    void f() throws AException;
}
interface InterfaceB{
    void f() throws BException;
}
interface InterfaceC extends InterfaceA, InterfaceB {
    void f();                                     //correct one
    void f() throws AException;                   //cannot pass compile
    void f() throws BException;                   //cannot pass compile
    void f() throws AException, BException;       //cannot pass compile
}

InterfaceC中的方法f()只能在{AException}和{BException}的交集处引发异常,因此没有异常。该规则限制了方法可以解决的异常。

interface InterfaceA{
    void f() throws AException, CException;
    void g() throws AException, CException;
}
interface InterfaceB{
    void f() throws BException, CException;
    void g() throws BException, CException;
}
interface InterfaceC extends InterfaceA, InterfaceB {
    void g();
}
public class C implement InterfaceC {
    public void f() {}
    public void g() {}
    public static void main(String[] args) {
        InterfaceC interfaceC = new C();
        C c = new C();
        interfaceC.f();                          //cannot pass compile, must handle Exception CException
        c.f();                                   //compile passed
        interfaceC.g();                          //compile passed
    }
}

InterfaceC中的方法f()未声明,因此该方法是使用{CException}的例外列表,InterfaceA的{AException,CException}和InterfaceB的{BException,CException}的交集自动生成的。 IntrefaceC中的方法g()和类C中的方法f()都声明为没有任何异常,因此不需要任何异常处理即可通过编译。