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

Java 编译器在检查的异常上未显示任何错误,java,exception,core,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

我正在处理检查过的异常,在这两者之间,我发现了一个例子:编译器在检查过的异常上并没有显示任何错误,并且工作正常

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"
    }
}

请告诉我原因,我在谷歌上搜索了很多次,但没有找到任何东西。

用面向对象的术语来说,当你编程到一个接口(即实现一个接口或扩展一个接口)时,你不能比接口更严格。但是,您可以减少限制。因此,在您的示例中,接口的方法可能会也可能不会引发FileNotFoundException和/或InterruptedException,但您的实现方法不会引发异常。请注意,如果您的实现的方法引发FileNotFoundException和/或InterruptedException,则完全可以,但如果它引发其他异常,则不允许。这意味着您的实现的限制性可以等于或小于接口,但不能比接口更严格

还要注意,当有人通过扩展接口类型(C)的变量或类类型(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
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
    }
}
更多澄清: C.f()不抛出异常的原因是它的父接口抛出不同的异常。因此,根据“接口的实现或扩展不能限制得更严格,但可以限制得更少”的论点,C.f()限制更少的唯一方法是不抛出异常。否则,它将比至少一个其父接口更具限制性。 另一方面,如果C的双亲抛出相同的异常,那么C.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
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
    }
}

这个问题的答案是正确的,但我想补充一些澄清。各种评论和回答都表明,在准则中

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()
引发的可能检查异常集是其两个超级接口引发的检查异常集的交集。

方法可以引发的检查异常集是其声明在所有适用类型中引发的检查异常集的交集,而不是联合[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()只能在{AEException}和{BEException}的交集处引发异常,因此它是none。该规则限制了方法可以引发的异常

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()都是无异常声明的,因此无需进行异常处理即可通过编译。

我不是Java方面的专家,但
抛出异常
只是声明一个方法可以抛出某个异常,而不一定会
不会引发异常。因为
C.f
A.f
,所以它不能引发
InterruptedException
。因为
C.f
B.f
,所以它不能引发
FileNotFoundException
。因此
C.f
不能引发任何选中的异常,所以你不必捕获任何异常。不,如果你把B改为C在语句C obj=new Test()中,您将得到一个有趣的错误观察结果!@TimBiegeleisen这与实现无关(
Test.f
).这是关于接口方法
C.f
。与您的建议相反,方法
B.f
不允许抛出
FileNotFoundException
中断异常
无法抛出任何异常,如问题中的代码所示。仍然没有真正回答问题,因为您所说的实现没有抛出异常;但问题是
C.f()
无法抛出任何已检查的异常(甚至没有查看实现).在问题中给出的示例中,C.f()无法引发任何已检查的异常。但如果A.f()和B.f()引发了相同的异常,则C.f()还需要抛出该异常。但是,即使在这种情况下,实现也不需要抛出任何异常。我试图给出一个概括的答案。我编辑了我的答案以澄清这一点。