何时捕获异常(高级别与低级别)



>我创建了以下类:

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

这三个子类可以引发异常(创建文件、写入文件等(。

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

其次,我有一个解析设置文件的类。我已经使用单例模式(运行时只有一个实例(制作了它。当然,在此类中可能会出现异常(NullPointerException和IOException(。

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

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

Liskov 替换原则的一部分指出:

类型的方法不应引发任何新的异常,除非这些异常本身是由超类型的方法引发的异常的子类型。

在客户端代码中将一种类型替换为另一种类型时,任何异常处理代码仍应正常工作。

如果您选择使用已检查的异常,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
        }
    }
}

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

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

这表明您应该在方法上throws异常,因为您不知道在该阶段如何处理异常。

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

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

最新更新