我很难理解将Exceptions传播到调用堆栈的概念或实际有用性。我得到了如何创建它们,但我真的不知道它们何时会被使用,就像在一个简单的现实世界的数学应用程序中那样。
public void method1(){
try{
method2();
}
catch(Exception e){
e.printStackTrace();
}
}
public void method2(){
try{
throw new Exception();
}
finally{
System.out.println("no exception, try cleanup");
}
}
我知道这基本上是如何工作的,虽然它可能会涉及更多的异常和函数,但我并没有真正意识到使用它们而不仅仅是捕获每个函数。
答案 0 :(得分:3)
...但我并没有真正明白使用这些而不只是在每个功能中都有捕捉。
重点是调用堆栈的下一个函数可能不知道如何处理异常。例如:
public class Test {
public Object doSomething(String source) throws IOException {
try (InputStream is = openAsStream(source)) {
// ... read and process stuff
return ...
}
}
public InputStream openAsStream(String name) throws IOException {
String fileName = // ... do something with 'name'
return new FileInputStream(name);
}
public static void main(String[] args) {
// ...
Test t = new Test();
try {
t.doSomething(args[0]);
} catch (IOException ex) {
System.err.println("Cannot handle '" + args[0] + "'");
}
}
}
openAsStream
调用可能引发FileInputStream
的{{1}}构造函数。 IOException
方法无法从此恢复,因此它可以传播。 openAsStream
方法也不知道如何处理它,因此它允许它传播。最后,异常到达doSomething
...它知道如何向用户解释问题。
现在您可以编写main
来捕获openAsStream
,打印错误消息并返回IOException
。但那将是一个很大的错误:
null
没有(并且不应该)知道是否/如何向用户报告问题。
如果它向调用者返回openAsStream()
,则调用者必须测试以查看调用的结果是否为null
...并采取其他操作。
关键是方法应该只处理在该级别可以充分处理的异常。其他人应该被允许传播。 (或者可能包含在另一个例外中......如果这是API设计所需要的。)
答案 1 :(得分:1)
有时,生成异常的代码不知道如何正确处理它。如果你处于一个事务代码中,并且某些东西爆炸了,那么该方法/组件可能无法做更多的事情而不是简单地记录异常,如果它试图处理它。另一方面,一个或多个层可能会尝试重新建立连接,或者向请求者提供详细的错误响应。
答案 2 :(得分:1)
调用者通常有适当的上下文来处理问题,因为执行生成异常的操作的代码没有。假设我是一个想要将一些数据写入文件的高级程序。我正在调用的低级服务,让我们称之为writeFile()可以出于各种原因抛出IOException。
编写writeFile()的人将不知道将使用writeFile()的上下文。如果writeFile()失败,它是否应该尝试重写文件?它应该尝试多少次?它应该放弃吗?因为在完成某项任务的方案中编写低级函数writeFile()的上下文的程序员在杂草中是如此遥远,程序员无法预测调用者将如何处理错误条件。
而不是试图猜测调用者如何处理错误(一个不可能完成的任务),writeFile()的程序员向客户端调用writeFile()表明存在一些需要的“开放式问题”问题出现时回答。每个问题都由一个异常类表示,当客户端程序员捕获该异常时,客户端程序员正在使用客户端程序员可能永远不会希望拥有的上下文来回答该开放式问题。
简而言之,如果您看到一个列出已检查异常的方法,那么编写该异常的程序员会说“任何调用此方法的人都会有适当的上下文来决定如何处理该异常情况。我会这么做不“。
答案 3 :(得分:1)
默认情况下,异常传播会使您的代码在错误上快速失败。
考虑异常传播的替代方法 - 返回错误代码。如果代码的调用者,无意或有意,不测试错误代码,那么他们可以使用您的方法,而不是意识到您的对象现在处于不可用状态,并继续调用方法并导致未定义的行为/内存损坏。如果你抛出一个异常,那么如果调用者忘记捕获异常,那么他们不会做出可怕的事情,而是快速失败,程序员可以被告知它被抛出的地方,为什么以及如何应对它。例外是吵闹和讨厌的,因为它们表明需要需要的条件。