何时捕捉异常(高水平与低水平)?

时间:2016-02-03 13:28:43

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

我创建了以下类:

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

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

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

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

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

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

3 个答案:

答案 0 :(得分:3)

部分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
        }
    }
}

答案 1 :(得分:2)

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

  

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

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

答案 2 :(得分:1)

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

例如, 如果您的DAO课程中出现DataAccessException,那么您可以抓住&在你的DAO中记录这个,然后重新抛出一个传播给调用者类的自定义异常,然后调用者应该决定它需要对该异常做什么。