Java - 为什么类型参数不能在 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 */ {}

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

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

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

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

编辑: [*]正如 davidxxx 让我注意到的那样,这个类声明无法编译Throwable因为它不是一个界面。

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

有关其他信息,请参阅此问题 - 类型参数保留在方法和类上,但不保留变量。

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

另外,如果使用原始类型运行代码,您希望代码执行什么操作?您建议的方式,T将被替换为Throwable,并且catch块现在将捕获所有异常,而不仅仅是特定类型的异常。

此外,JLS 将CatchType指定为:

CatchType:
ClassType
ClassType | CatchType

其中不包括TypeArgument.

如果你真的想这样做,你可以抓住Throwable并使用instanceof或使用其Class来检查类型:

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

注意:捕捉ThrowableException通常被认为是非常糟糕的做法。

编辑:这是它在 C# 中的外观,以供参考。

最新更新