何时使用catch以及何时在异常处理中使用throws

时间:2014-09-09 02:36:06

标签: java exception-handling

问题不在于异常处理语法,而是在通过传播方法的过程中为异常编写catch块的正确位置。

public boolean validateUser(String username, String password) throws SQLException {
    Connection conn = dataSource.getConnection();
    boolean result = false;
    PreparedStatement pstmt = conn.prepareStatement("SELECT * FROM USERS WHERE   USERNAME=? AND PASSWORD=?");
    pstmt.setString(1, username);
    pstmt.setString(2, password);
    result = pstmt.executeQuery().next();
    conn.close();
    return result;
}

假设method1()调用method2()method2()调用上述方法。在上面的方法中,如果我处理异常,我必须返回一个值。假设我在catch块之后返回falsemethod2()误解了用户名或密码错误。

如果我没有处理,method2()将不会收到任何值,它的catch块将会执行,method1()会出现同样的问题。

现在您可以定义在哪里可以有效处理异常吗?

4 个答案:

答案 0 :(得分:2)

只有在您可以合理地从错误状态中恢复时,才应catch例外。在其他所有情况下,您都应该将其传播给调用者,并希望他能够以有意义的方式处理它。如果调用堆栈中没有人能够处理它,那么终止应用程序可能是正确的事情。

假设您正在编写带图标的图形用户界面。你有一个方法

Icon loadIcon(String filename) throws IOException;

从磁盘文件加载图标的图像。如果此I / O操作失败,则loadIcon无法从该错误中恢复。最好让异常传播。

在其他地方,你有另一种方法

void buildGUI();

填充用户界面。它将使用loadIcon根据当前选择的图标主题获取各种按钮的图标。如果加载一个图标失败,这将是导致整个GUI构建过程崩溃的一个不好的理由。在这里,我们应该捕获异常并尝试使用后备图标或显示一个空按钮。这将允许用户仍然使用该应用程序,并可能意识到缺少某些图标,从而修复其安装。

答案 1 :(得分:0)

如果方法X的记录的目的是调用可以抛出SomeCheckedException的方法Y,并且从方法X中抛出SomeCheckedException的唯一方法是那些X的调用者会期望,然后将X声明为throws SomeCheckedException并简单地让Y抛出的异常传播到X的调用者是合理的。然而,这不是一个非常普遍的情况。

如果X的目的是执行某些操作,虽然它碰巧使用方法Y来达到目的,但是X的文档中没有任何内容指定它将调用抛出SomeCheckedException的方法,那么X的事实调用可能抛出SomeCheckedException的方法应该被视为实现细节;它不应该暴露给来电者。在这种情况下,如果Y抛出一个SomeCheckedException,X应该捕获它,将其包装起来,并将其重新抛出为对X的调用者有意义的东西。

请注意,如果X只是声明throws SomeCheckedException,那么X的调用者就没有可靠的方法来区分由于期望的原因而抛出的SomeCheckedException与方法调用抛出的SomeCheckedException之间的区别。那个失败未被预料到的人。相比之下,如果调用X期望的方法可能抛出{{1}},则会将try / catch / throw块包装为调用者期望的类型,但是X不希望实际抛出该异常的类型包含在抛出“意外异常”异常的try / catch / throw块中,然后这些情况将被识别为不同。

答案 2 :(得分:0)

使用例外有利于短路并在出现问题时快速失败,这样一旦问题浮出水面,代码就不会在不再相关的情况下试图执行。

在您的示例中,您需要连接,预准备语句和结果集。这些抛出的例外情况大多是不可恢复的;如果在获取或使用其中任何一个时出现任何错误(SQL的语法错误,或结果集列名称不正确,或数据库出现故障,或连接超时等等),您就完成了。

在方法中捕获异常会很糟糕,因为除了从该方法获取结果之外,您拥有该方法之外的东西,如果查询失败,那么就没有必要继续进行。错误检查与快乐路径业务逻辑纠缠在一起,使代码更难阅读。

您需要抛出异常,直到它到达您尝试执行的整个业务操作之外的位置。

因此,一般的想法是确定工作单​​位,如果出现任何问题,必须放弃整个工作。然后,在该工作单元之外,您可以放置​​一个捕获异常的处理程序,并执行您需要的任何日志记录,通知等。

采用单元测试框架,例如JUnit或TestNG。执行测试用例对象的每个方法,如果从中抛出任何东西,则调用该方法的框架捕获它,确定是否是预期的,将结果保存给用户,然后继续。

同样在Web应用程序中,每个HTTP请求通常都是一个工作单元,任何抛出的异常都不会被捕获,直到它到达一个捕获从控制器层抛出的任何内容的全局处理程序。

对于Swing应用程序,您可以实现UncaughtExceptionHandler

当我说任何时,有一些特殊情况,例如:

  • jdbc对象关闭时抛出的异常不应该阻止业务逻辑被执行,也不应该传播(因为无法释放数据库上的资源不会影响应用程序中的任何内容),它们可以在它们发生的方法中记录和吃掉。

  • 流控制存在InterruptedExceptions,需要考虑到这一点,以便在线程中断时它可以快速响应。

  • 由用户操作引起的约束违规生成的SQL异常可以在控制器层中捕获并用于向用户提供反馈(反映其原因的Spring identifies SQLExceptions and wraps them in exceptions方式可以轻松处理此情况) 。

答案 3 :(得分:-3)

catch 几乎一直都在try块中,除非您使用 finally 。如果要将错误传播给调用者,则需要使用 throw 。如果您不想传播错误,可以捕捉它,而不是将其丢回。