【问题标题】:When to catch the exceptions (high level vs. low level)?何时捕获异常(高级与低级)?
【发布时间】:2023-03-28 11:35:01
【问题描述】:

我创建了以下类:

  • 抽象记录器类
  • 实现实际记录器的抽象记录器类的三个子类
  • 充当记录器接口的类

三个子类可以抛出异常(创建文件、写入文件等)。

我应该直接在三个子类中捕获异常还是在那里重新抛出并在接口中捕获它?或者可能在使用记录器接口的类中捕获?

其次,我有一个解析设置文件的类。我已经使用单例模式(运行时只有一个实例)做到了。当然在这个类中可能会发生异常(NullPointerException 和 IOException)。

我应该直接在此类中捕获这些异常还是将其重新抛出给该类的客户端?

我的一般问题是我不知道何时必须捕获异常以及何时重新抛出异常。

【问题讨论】:

  • 视情况和要求而定。
  • 这些记录器能否正确处理这些异常?如果没有,则传播它们。
  • Effective Java 2nd Ed 中第 61 条的推论(“抛出适合抽象的异常”)是您应该抛出异常如果它适合抽象,或者捕获它如果这更适合抽象。这在很大程度上取决于您要建模的内容。

标签: java exception exception-handling try-catch throws


【解决方案1】:

Liskov substitution principle 的一部分声明:

子类型的方法不应抛出新的异常,除非这些异常本身是超类型方法抛出的异常的子类型。

因此,当在客户端代码中用一种类型替换另一种类型时,任何异常处理代码都应该仍然有效。

如果您选择使用checked exceptions,Java 会为您强制执行此操作。 (不建议使用受检异常,但我将在此处使用来演示原理)。

这并不是说您应该捕获所有异常并进行转换。异常可能是意外的(即RuntimeExceptions 在检查异常环境中),您应该只翻译匹配的异常。

例子:

public class NotFoundException {
}

public interface Loader {
    string load() throws NotFoundException;
}

用法:

public void clientCode(Loader loader) {
   try{
      string s = loader.load();
   catch (NotFoundException ex){
      // handle it
   }     
}

这是一个很好的实现,它可以捕获一个可以捕获和转换的异常,然后传播其余的异常。

public class FileLoader implements Loader {
    public string load() throws NotFoundException {
        try{
          return readAll(file);
        } catch (FileNotFoundException ex) {
          throw new NotFoundException(); // OK to translate this specific exception
        } catch (IOException ex) {
          // catch other exception types we need to and that our interface does not
          // support and wrap in runtime exception
          throw new RuntimeException(ex);
        }
    }
}

这是翻译所有异常的糟糕代码,不需要满足 Liskov:

public class FileLoader implements Loader {
    public string load() throws NotFoundException {
        try{
          return readAll(file);
        } catch (Exception ex) {
          throw new NotFoundException(); //assuming it's file not found is not good
        }
    }
}

【讨论】:

    【解决方案2】:

    当您知道如何处理该异常时,您应该捕获该异常。

    我的一般问题是我不知道何时必须捕获异常以及何时重新抛出异常。

    这建议您应该 throws 方法上的异常,因为在那个阶段您不知道如何处理异常。

    【讨论】:

      【解决方案3】:

      在我看来,异常应该总是传播回调用者。您始终可以从类本身捕获、记录然后重新抛出相同的或自定义的异常,但最终它应该由调用者处理。

      例如, 如果DataAccessException 出现在您的 DAO 类中,那么您可以在您的 DAO 中捕获并记录它,然后重新抛出一个自定义异常,该异常会传播到调用者类,然后调用者应该决定它需要对该异常做什么。

      【讨论】:

      • 这只是你的意见。异常不必总是被传播,无论是通过设计还是通过语法。
      • @Stultuske 是的,纯粹是我的意见。
      猜你喜欢
      • 2013-06-26
      • 1970-01-01
      • 2011-04-14
      • 1970-01-01
      • 1970-01-01
      • 2020-08-14
      • 1970-01-01
      • 1970-01-01
      • 2011-09-26
      相关资源
      最近更新 更多