Java 列出所有未报告的异常(包括包含已声明异常的超类的异常)

Java 列出所有未报告的异常(包括包含已声明异常的超类的异常),java,exception,static-analysis,throws,Java,Exception,Static Analysis,Throws,考虑以下场景 public class A extends Throwable {} public class B extends A {} public class C { public void f() throws A, B { // Some condition throw new A(); // Some condition throw new B(); } voi

考虑以下场景

public class A extends Throwable {}

public class B extends A {}

public class C
{
    public void f() throws A, B
    {
        // Some condition
            throw new A();

        // Some condition 
            throw new B();
    }

    void g() 
    {
        f();
    }
}
使用上述代码,编译器将警告不捕获(或不声明为抛出)

如果我将g改为

void g() throws A
然后我就没有收到更多的警告(B通过捕捉A而被隐式捕捉)

有没有办法让编译器报告所有未捕获的异常,包括基类异常(如这里的B)

一种方法是更改
g()
,并将其声明为

public void f() throws B, A
在这种情况下,编译器将首先报告B&一旦我将B添加到
g
throw
规范中,它将报告A

但这是痛苦的,因为

  • 这是一个两步过程
  • 我可能无法控制功能
    f
    来更改其投掷规格
有没有更好的方法让编译器报告所有异常

我并不是说编译器在这里做错了什么——我要问的是——“有没有办法让编译器报告所有的异常?”。或者有没有一个工具可以帮助我自动获取这些信息

函数
f
在不同情况下抛出A和B。如果我是
g
的作者,我不会意外地抑制调用
g
可能抛出B的信息-如果我将
g
声明为
抛出A
而不是声明为
抛出B,A
,就会发生这种情况。有没有办法让编译器检测到这一点并警告我


再次强调,我并不是说编译器没有警告我这一点是做错了什么。我要问的是,是否有一种方法可以让编译器实现我想要的功能。或者是一个报告这一点的工具?

我并不是想让人觉得我是在自命不凡。我可能会说很多你已经知道的东西。但是请耐心听我说,我试图解释为什么使用编译器警告无法解决您的问题

从彼此派生两个类,不管它们是否是异常类,这意味着它们处于is-a关系中。例如:

public class Vehicle {}

public class Car extends Vehicle {}

public class Boat extends Vehicle {}
表示:
车辆
是一辆
车辆
<代码>船是一种
车辆

通过
抛出
,或者更直接地说,
捕获
(稍后),您可以指定要抛出/捕获的类型。现在,假设
车辆
源自
异常
,您可以执行以下操作:

try
{
    // ...
}
catch (Car c)
{
    // You caught a car. Not any vehicle, a real, honking car.
}
然而,通过这样做:

try
{
    // ...
}
catch (Vehicle v)
{
    // You caught some vehicle. Any vehicle.
}
您指定您不关心是否捕获汽车、船只、自行车或任何东西,只要它是可移动的,可以运送乘客或货物。因为汽车是一种交通工具。船是一种交通工具

总之,您试图做的事情完全违背了面向对象方法的理念。您不能让编译器报告任何“抑制”或“隐藏”异常,因为它们确实不是。使用
抛出
,它们被定义得非常清楚;使用
捕获
,它们被处理得非常清楚。因此,编译器甚至不理解您的问题,更不用说提供一些方法来防止它了

正如这些评论所说,静态代码分析几乎是完成您想要做的事情的唯一选择。我在这种场合用过的东西是。因为您想要的是非常不寻常的,所以我不认为Checkstyle对您想要的东西有预定义的检查。事实上,它确实有一个检查


因此,您可能必须为它编写自己的检查,但Checkstyle允许您轻松地完成此操作。我将首先阅读
RedundantThrows
检查的源代码,然后执行与之相反的操作。如果没有在方法
throws
签名中列出所有抛出的已检查异常,这将使自定义检查失败。

这是编译器特有的行为。当您的场景位于Eclipse中时,编译器将在错误列表中告诉您这两个异常,尽管工具提示中只显示一个异常。更有趣的是,当使用自动修复时,无论是添加
catch
子句还是
throws
声明,Eclipse都会同时添加这两个(换句话说:所有异常),忽略异常之间的任何子类关系。声明的顺序对该行为没有影响。因此,您可能只想使用Eclipse:^)。

编译器在这里没有执行任何“警告”。根据定义的Java语义,它会给您一个编译错误。同样的语义表明,您的其他示例是完全合法的,因此没有什么需要警告的。@EJP,我并不是说编译器没有做正确的事情。我问的是如何让编译器以不同的方式运行。@user93353在第二种情况下,
抛出B(扩展A),A是冗余的;正确的响应是捕获
A
,而Java系统并不关心(也不能让它关心)您是否也捕获
B
。如果您正在捕获
IOException
,那么如果您也有一些有用的方法来以不同的方式处理
eofeexception
,那么对您有好处,但是期望编译器警告您
IOException
的每个未得到特殊处理的子类是不明智的(或者正在使用
instanceof
而不是
catch
语句处理)@chrylis-我知道Java系统不在乎-我想问的是-有没有办法让它在意?如果B非常重要,应该明确地处理它,不要从a中派生出来。你完全误解了我的问题-我不是在问一种在我抓到
车辆时报告未抓到的
汽车
。我是在问当我没有捕获任何异常时,一种报告未捕获的
Car
的方法,并且
throw spec
按照
throws Vehicle,Car
的顺序声明异常。不,实际上我没有,但显然你误解了我的答案。我使用了
catch
try
{
    // ...
}
catch (Vehicle v)
{
    // You caught some vehicle. Any vehicle.
}