首页 文章

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

提问于
浏览
3

我创建了以下类:

  • 抽象 Logger 类

  • 实现实际 Logger 的抽象 Logger 类的三个子类

  • 用作 Logger 接口的类

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

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

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

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

我的一般问题是,我不知道什么时候必须 grab 异常以及何时重新抛出异常 .

3 回答

  • 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

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

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

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

  • 2

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

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

相关问题