[英]Exceptions propagate up Call Stack
我很难理解让异常在调用堆栈中传播的概念或真正的用处。 我知道如何创建它们,但是我真的不知道何时使用它们,就像在一个简单的现实世界中的数学应用程序中一样。
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");
}
}
我认为这基本上是它的工作方式,尽管它可能更多地涉及更多的异常和函数,但是我并没有真正使用它们而不是仅仅捕获每个函数的意义。
...但是我真的不明白使用这些方法的意义,而不仅仅是在每个函数中都有问题。
关键是调用栈中的下一个函数可能不知道如何处理该异常。 例:
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
构造函数,该构造函数可能会抛出IOException
。 openAsStream
方法无法从中恢复,因此它可以传播。 doSomething
方法也不知道如何处理,因此它可以传播。 最后,异常到达main
...,它知道如何向用户解释问题。
现在您可以编写openAsStream
来捕获IOException
,打印一条错误消息并返回null
。 但这将是一个大错误:
openAsStream()
不(也不应该 )知道是否/如何向用户报告问题。
并且,如果它向调用方返回null
,则调用方必须进行测试以查看调用结果是否为null
...并采取替代措施。
关键是方法只应处理可以在该级别上适当处理的异常。 应该允许其他人传播。 (或者包裹在另一个异常中……如果那是API设计所要求的。)
有时,生成异常的代码不知道如何正确处理它。 如果您在一段事务代码中,并且发生了故障,那么该方法/组件可能无法做更多的事情,而不仅仅是在尝试处理该异常时记录该异常。 另一方面,一层或多层可以尝试重新建立连接,或向请求者提供详细的错误响应。
通常,调用者具有适当的上下文来处理问题,而执行生成异常的操作的代码则没有。 假设我是一个高级程序,希望将一些数据写到文件中。 我正在调用的低层服务,我们称它为writeFile()可以由于多种原因引发IOException。
写writeFile()的人不会知道将在哪个上下文中使用writeFile()。 如果writeFile()失败,是否应该尝试重新写入文件? 它应该尝试几次? 它应该放弃吗? 因为在完成某些任务的方案中编写低级函数writeFile()的上下文的程序员陷入了困境,所以程序员无法预期调用者将如何处理错误情况。
而不是试图猜测调用者将如何处理错误(一项不可能的任务),writeFile()的程序员向调用writeFile()的客户端指示了一些“未解决的问题”,当问题出现时需要回答出现。 每个问题都由一个异常类指示,当客户程序员捕获到该异常时,客户程序员将使用客户程序员永远都不会希望拥有的上下文来写一个未解决问题的答案。
简而言之,如果您曾经看到一个列出了已检查异常的方法,则编写该异常的程序员会说:“ Whomever调用此方法将具有适当的上下文,可以决定对该异常情况如何处理。我不会。”
默认情况下,异常传播使您的代码对错误进行快速失败检查。
考虑异常传播的替代方法-返回错误代码。 如果代码的调用者无意或有意地未测试错误代码,则他们可以使用您的方法,不知道您的对象现在处于无法使用的状态,并继续调用方法并导致未定义的行为/内存损坏。 如果您引发了异常,那么如果调用者忘记捕获异常,那么它们就不会做可怕的事情,而是迅速失败,并且可以向程序员发出有关抛出该异常的原因,原因和处理方法的警报。 异常大声且令人讨厌,因为它们表示需要考虑的条件。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.