【问题标题】:List all unreported exceptions (including exceptions which super classes of declared exceptions)列出所有未报告的异常(包括声明异常的超类的异常)
【发布时间】:2013-09-24 01:28:59
【问题描述】:

考虑以下场景

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();
    }
}

使用上面的代码,编译器会警告不捕获(或不声明为抛出)

C.java:17: unreported exception A; must be caught or declared to be thrown
        f();
         ^

如果我通过将 g 更改为

来解决此问题
void g() throws A

然后我不会再收到警告(B 会被 A 隐式捕获)

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

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

public void f() throws B, A

在这种情况下,编译器将首先报告 B,一旦我将 B 添加到 gthrow 规范中,它将报告 A。

但这很痛苦,因为

  • 这是一个两步过程
  • 我可能无法控制函数 f 来更改它的投掷规格。

有没有更好的方法让编译器报告所有异常?

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

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

再次,我并不是说编译器没有警告我这样做是错误的。我要问的是是否有办法让编译器做我想做的事。或者报告这个的工具?

【问题讨论】:

  • 编译器在这里没有做任何“警告”。它根据 Java 的定义语义给你一个编译错误。这些相同的语义表明您的其他示例是完全合法的,因此无需警告。
  • @EJP,我并不是说编译器没有做正确的事情。我在问如何让编译器做不同的事情。
  • @user93353 在第二种情况下,throws B (extends A), A 是多余的;正确的响应是捕获A,Java 系统不关心(也不能关心)您是否也更具体地捕获B。如果您正在捕获IOException,那么如果您也有某种方法可以有效地以不同方式处理EOFException,那么这对您有好处,但是期望编译器警告您IOException 的每个最后一个子类是不明智的获得特殊待遇(或正在使用instanceof 而不是catch 语句处理)。
  • @chrylis - 我知道 Java 系统不在乎 - 我要问的是 - 有没有办法让它在乎?
  • 如果 B 如此重要以至于应该明确处理,请不要从 A 派生它。

标签: java exception static-analysis throws


【解决方案1】:

我并不想显得傲慢自大或其他任何事情。我可能会说很多你已经知道的东西。但请耐心等待,我会尝试解释为什么使用编译器警告无法解决您的问题。

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

public class Vehicle {}

public class Car extends Vehicle {}

public class Boat extends Vehicle {}

表示:Car 是一个 VehicleBoat 是一个 Vehicle

使用throws,或更重要的是catch(稍后),您可以指定要抛出/被捕获的类型。现在,假设Vehicle 派生自Exception,您可以这样做:

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

您指定您不关心您是否搭乘汽车、船只、自行车或其他任何东西,只要它是移动的并且可以运送乘客或货物。因为汽车车辆。而船是一种交通工具。

总而言之,您尝试做的事情完全违背了面向对象方法的理念。您不能让编译器报告任何“抑制”或“隐藏”异常,因为它们真的不是。对于throws,它们的定义非常明确,而对于catch,它们的处理非常多。所以编译器甚至不理解你的问题,更不用说提供一些方法来防止它了。

正如 cmets 所说,静态代码分析几乎是完成您想做的事情的唯一选择。我在这些场合使用过的东西是Checkstyle。由于你想要的东西很不寻常,我认为 Checkstyle 没有预定义的检查你想要的东西。事实上,它确实检查了the exact opposite

因此,您可能必须为它编写自己的检查,但 Checkstyle 很容易做到这一点。我将从阅读RedundantThrows 检查的源代码开始,然后做与它相反的事情。如果您没有在方法 throws 签名中列出所有抛出的检查异常,这应该会使您的自定义检查失败。

【讨论】:

  • 你完全误解了我的问题——我不是要在我抓到Vehicle 时报告未捕获的Car。当我没有发现任何异常并且throw specthrows Vehicle, Car 的顺序声明异常时,我正在寻求一种方法来报告未捕获的Car
  • 不,实际上我不是,但显然你误解了我的回答。我使用catch 而不是throws 只是因为它更容易理解。问题和答案完全相同。就编译器而言,throws Vehicle, Car 是多余的,因为 CarVehicle。所以throws Vehicle 已经包含了CarBoat 以及Vehicle 的所有可能的派生词。我回答的重点是我现在用粗体写的那句话。
  • 我想要一种方法来找到这些信息——不管它来自编译器还是任何其他工具。
  • 当我写下我的答案时,你只是在寻求一种让编译器做你想做的事情的方法;)我只是在我的答案中添加了一些关于工具的东西。
  • 仅供参考 - Eclipse Java 编译器准确地报告了我想要的。
【解决方案2】:

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

【讨论】:

  • 好的 - 让我尝试通过 Eclipse 使用它。
  • 更好的是,我下载了 ecj - Eclipse Java 编译器 - 现在我什至不必使用 Eclipse IDE 来获取错误。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多