4

我很难完全理解让异常传播到调用堆栈的概念或真正的用处。我知道如何创建它们,但我真的不知道它们什么时候会被使用,比如在一个简单的现实世界数学应用程序中。

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");
      }
}

我知道这基本上就是它的工作方式,尽管它可能会更多地涉及更多的异常和函数,但我并没有真正理解使用这些而不是在每个函数中都有捕获。

4

4 回答 4

5

...但我并没有真正理解使用这些功能,而不仅仅是在每个函数中都有捕获。

关键是调用堆栈上的下一个函数可能不知道如何处理异常。例子:

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 设计所要求的。)

于 2013-03-26T02:19:42.207 回答
2

默认情况下,异常传播使您的代码在错误时快速失败。

考虑异常传播的替代方法 - 返回错误代码。如果您的代码的调用者意外或故意不测试错误代码,那么他们可能会使用您的方法,而不知道您的对象现在处于不可用状态,并继续调用方法并导致未定义的行为/内存损坏。如果您改为抛出异常,那么如果调用者忘记捕获异常,那么它们不会做可怕的事情,而是快速失败,并且程序员可以被警告它被抛出的位置、原因以及如何处理它。异常是响亮而令人讨厌的,因为它们表明需要考虑的条件。

于 2013-03-26T02:02:51.393 回答
1

通常,调用者有适当的上下文来处理问题,而执行生成异常的操作的代码却没有。假设我是一个高级程序,想要将一些数据写入文件。我正在调用的低级服务,我们称之为 writeFile() 可以出于各种原因抛出 IOException。

编写 writeFile() 的人将不知道 writeFile() 将被使用的上下文。如果 writeFile() 失败,它是否应该尝试重新写入文件?它应该尝试多少次?它应该放弃吗?因为在完成某些任务的方案中编写低级函数 writeFile() 的上下文的程序员已经陷入困境,程序员不可能预料到调用者会如何处理错误情况。

writeFile() 的程序员不是试图猜测调用者希望如何处理错误(不可能的任务),而是向调用 writeFile() 的客户端指示有一些“未解决的问题”需要在出现问题时回答出现。每个问题都由一个异常类指示,当客户端程序员捕获该异常时,客户端程序员正在使用客户端程序员永远不希望拥有的上下文来编写对该开放问题的答案。

简而言之,如果你看到一个方法列出了一个已检查的异常,那么编写该异常的程序员会说“调用此方法的人将有适当的上下文来决定如何处理该异常情况。我没有。”

于 2013-03-26T01:58:34.927 回答
1

有时生成异常的代码不知道如何正确处理它。如果您在一段事务代码中,并且发生了故障,则该方法/组件可能无法做更多的事情,而只是在尝试处理异常时记录该异常。另一方面,在一层或多层之上,您可能能够尝试重新建立连接,或向请求者提供详细的错误响应。

于 2013-03-26T01:48:55.757 回答