为什么不捕获异常的代码允许捕获检查异常?
问题内容:
在Java中,引发 检查
异常(Exception或其子类型-
IOException,InterruptedException等)的方法必须声明 throws 语句:
public abstract int read() throws IOException;
不声明throws
语句的 方法不能 引发检查的异常。
public int read() { // does not compile
throw new IOException();
}
// Error: unreported exception java.io.IOException; must be caught or declared to be thrown
但是在Java中使用安全方法捕获检查的异常仍然合法:
public void safeMethod() { System.out.println("I'm safe"); }
public void test() { // method guarantees not to throw checked exceptions
try {
safeMethod();
} catch (Exception e) { // catching checked exception java.lang.Exception
throw e; // so I can throw... a checked Exception?
}
}
其实没有 有点可笑:编译器知道 e 不是检查的异常,因此可以将其重新抛出。事情甚至有些荒谬,此代码无法编译:
public void test() { // guarantees not to throw checked exceptions
try {
safeMethod();
} catch (Exception e) {
throw (Exception) e; // seriously?
}
}
// Error: unreported exception java.lang.Exception; must be caught or declared to be thrown
第一个片段是提出问题的动机。
编译器知道不能将检查的异常抛出到安全的方法中-因此也许应该只捕获未检查的异常?
回到 主要问题 -是否有任何理由以这种方式实现捕获受检查的异常?这仅仅是设计中的缺陷,还是我缺少一些重要因素-
可能是向后不兼容?如果只RuntimeException
允许在这种情况下被捕获,可能会出什么问题?例子是极大的赞赏。
问题答案:
如果catch子句可以捕获经过检查的异常类E1,则是编译时错误,并且与catch子句相对应的try块不能抛出作为E1的子类或超类的经过检查的异常类,除非E1是Exception或Exception的超类。
我猜想这个规则起源于Java 7早于Java
7,当时不存在多类别。因此,如果您有一个try
可能引发大量异常的块,则捕获所有内容的最简单方法是捕获一个通用的超类(在最坏的情况下Exception
,或者Throwable
您也想捕获Error
s)。
请注意,您可能 不会 捕获与实际抛出的异常完全无关的异常类型-
在您的示例中,捕获该异常类型的任何子类Throwable
都不RuntimeException
是一个错误:
try {
System.out.println("hello");
} catch (IOException e) { // compilation error
e.printStackTrace();
}
由OP编辑:
答案的主要部分是问题示例仅适用于Exception类的事实。通常,在代码的随机位置不允许捕获检查的异常。对不起,如果我混淆了使用这些示例的人。