Java - 为什么不能在catch子句中键入参数?

时间:2017-07-24 14:10:23

标签: java generics try-catch

我知道泛型类型不能扩展Throwable,我知道这没有意义,因为类型擦除(异常只在运行时抛出)和其他微妙的东西。

然而,Java允许类型参数受Throwable限制,实际上以下代码是合法的

class MyClass<T extends Throwable> { /*body of the class */ }

什么是非法的是在catch子句中使用T参数

try { //do something that throws exception //  }
catch(T e) /* ILLEGAL!!! DOESN'T COMPILE */ {}

我能理解这个约束的唯一原因是type参数,因为擦除,被它的边界类型取代,在本例中是Throwable。 但是类型参数也可能受到多个边界类型的限制,所以我可能会出现这种情况

class MyClass<T extends Object & Throwable> [*]

在这种情况下T在被Object擦除后被替换,我知道Object(不是Throwable类型)变量不能在catch子句中

让我知道这是否是这个Java约束的原因。感谢。

编辑: [*]由于davidxxx让我注意到,这个类声明没有编译,因为Throwable不是接口。

1 个答案:

答案 0 :(得分:7)

运行时无法检查捕获的异常的类型是否与T匹配,因为它不知道T是什么。

有关其他信息,请参阅this question - 类型参数保留在方法和类中,但不保存在变量中。

catch块的要点是您可以通过向异常类型提供特定行为来处理异常。这也是您可以为单个catch提供多个try块的原因。如果没有特定的异常类型,则无法执行正确的catch块。

此外,如果您使用原始类型运行代码,您希望代码做什么?建议的方式,T将替换为Throwable,而catch块现在会捕获所有异常,而不仅仅是某种类型的异常。

此外,JLSCatchType指定为:

CatchType:
    ClassType
    ClassType | CatchType

不包含TypeArgument

如果确实想要这样做,您可以抓住Throwable并使用instanceof或使用Class检查类型:

try {
    doSomethingDangerous();
} catch (Throwable t) {
    if (t instanceof IOException) {
        handleIoException(t);
    } else if (...) {
        ...
    } else {
        handleOther(t);
    }
}

注意:Catching Throwable or Exception is usually considered very bad practice

修改:here's what it looks like in C# for possible reference