【问题标题】:Interface implementation launches different exceptions接口实现启动不同的异常
【发布时间】:2013-05-16 05:14:44
【问题描述】:

我有一个界面

public interface DataDAO {
     public void doSomething() throws Exception;
}

假设有两种实现,一种使用数据库获取数据,另一种使用 Web 服务。

public class DataDAOJdbc implements DataDAO {
    public void doSomething() throws Exception {
         //Implement
    }
}

public class DataDAOWebService implements DataDAO {
    public void doSomething() throws Exception {
         //Implement
    }
}

正如您已经看到的,问题在于启动了超级通用异常。由于两种实现都需要引发相同类型的异常。

Jdbc 实现实际上只会引发 SQLException,而 Webservice 实现只会引发 IOException。

问题是,我怎样才能使界面更优雅,以便捕获适当的异常?

我首先想到的是创建自己的异常,并在接口级别声明它

public interface DataDAO {
  public void doSomething() throws MyCoolException;
}

然后,当然相应地实施。

问题是,这有意义吗?我从未创建过自己的异常,所以我不确定这是否有意义。另外,创建 MyCoolException 时应该注意什么?

【问题讨论】:

  • 如何从 Spring 中获取一些灵感并将它们包装在 RuntimeExceptions 中。
  • @AjayGeorge 好吧,我希望上层处理这些异常,因此将它们设为 RuntimExceptions 对我无效,如果我错了,请纠正我 :)
  • 你可以继承 RuntimeExceptions 然后像在春天一样创建一个DataAccessException

标签: java oop exception interface


【解决方案1】:

我首先想到的是创建自己的异常,并在接口级别(...)声明它,这有意义吗?

是的,这是有道理的,我认为这是处理这些情况的最佳方式。

我将为此提供一个启动示例(基于您当前的代码):

public class MyCoolException extends Exception {
    public MyCoolException() {
    }
    public MyCoolException(String message) {
        this.message = message;
    }
}

public interface DataDAO {
    public void doSomething() throws MyCoolException;
}

public class DataDAOJdbc implements DataDAO {
    public void doSomething() throws MyCoolException {
         //Implement
         try {
         } catch (SQLException e) {
             //handle the exception
             logger.error("Error!", e);
             //throw your custom exception
             throw new MyCoolException(e.getMessage());
         }
    }
}

public class DataDAOWebService implements DataDAO {
    public void doSomething() throws MyCoolException {
         //Implement
         try {
         } catch (IOException e) {
             //handle the exception
             logger.error("Error!", e);
             //throw your custom exception
             throw new MyCoolException(e.getMessage());
         }
    }
}

【讨论】:

  • 嗯,这是一个挑剔的问题,但我建议用MyCoolException 包装原因异常(而不是其消息字符串),并在处理MyCoolException 时等待记录整个故事。
  • 我完全同意 Paul 的观点,我什至会说这是编写自己的异常时要考虑的最重要的事情(尤其是,如果它是为了包装另一个例外):如果没有最初的原因,您会丢失 很多 信息,这些信息在调试任何问题时可能是绝对重要的。
  • @PaulBellora 我同意你们的观点,这就是为什么我说这是一个基本示例并在重新抛出自定义异常之前记录异常。
【解决方案2】:

可以使用泛型类型来定义抛出的接口:

public interface DataDAO<E extends Throwable> {
  public void doSomething() throws E;
}

那么您的实现将如下所示:

public class DataDAOJdbc implements DataDAO<JDBCException> {
    public void doSomething() throws JDBCException {
         //Implement
    }
}

public class DataDAOWebService implements DataDAO<WebServiceException> {
    public void doSomething() throws WebServiceException {
         //Implement
    }
}

但是,这样做的缺点是您不能再处理所有异常,除非您只捕获 Exception(这几乎否定了整个观点)。

【讨论】:

  • 但假设 OP 想要编写接口而不是实现,这根本无助于调用站点。
  • 这种方法破坏了多态性。应该使用自定义异常。
  • @Noofiz 这有点含糊 - 你能解释一下吗?
  • @PaulBellora:这就是我在最后一句话中所暗示的。我并不是说它是完美的方式,它只是另一种选择。
  • @Paul Bellora,我的意思是在调用 DAO 时,我应该期待一个特殊的 DAOExceptio 而不仅仅是 Throwable。下一步该怎么做? “if(Throwable instanceof ...)else if .. else if”在catch块中?在 DAO 接口声明中应指定实体类型,而不是异常。对于所有 DAO 实施,异常应该是通用的。
【解决方案3】:

这有意义吗?

是的,确实如此。通过声明doSomething 抛出一个特定的检查异常,您向方法的调用者发出信号,他们只需要捕获和处理该特定异常。通过声明普通的throws Exception,将鼓励调用者捕获并处理所有Exceptions,甚至包括像NullPointerException 这样的运行时异常。

创建 MyCoolException 时应该注意什么?

可以这么简单:

public final class MyCoolException extends Exception {

    public MyCoolException(Throwable cause) {
        super(cause);
    }
}

因此,您的自定义异常将简单地充当原因异常的包装器,无论它可能是什么。如果可能,您可以添加一条包含可能有助于调试的附加信息的消息。当MyCoolException 被捕获时,您可以通过调用getCause() 将其解包,或者将其传递给对日志框架的调用(其堆栈跟踪将包含原因异常)。

【讨论】:

    猜你喜欢
    • 2013-03-14
    • 1970-01-01
    • 1970-01-01
    • 2016-01-01
    • 1970-01-01
    • 1970-01-01
    • 2010-09-06
    • 2021-02-22
    • 1970-01-01
    相关资源
    最近更新 更多