异常使用异常

时间:2009-11-20 11:00:46

标签: exception-handling refactoring

这是一个重构问题。

try
{
  string line = GetFirstLineFromFile(); //Gets first line from a text file, this line would be a number.
  int value = ConvertToInteger(line); // Gets the integer value from the string.
  int result = DivideByValue(value); // Divides some number with the value retrieved.
}
catch(Exception ex)
{
}

我主要担心的是,在这种情况下,异常处理的最佳方法是什么。当然,将整个事情包装在一个试试中就像是说我希望对所有事情都有例外。我们必须在某个地方找到一般的例外吗?

3 个答案:

答案 0 :(得分:2)

只是不要抓住“一般例外”。

如何处理任何异常并知道如何使应用程序保持干净状态? 它隐藏了错误,这是一个非常糟糕的主意。

catch (Exception)上阅读此系列帖子。

答案 1 :(得分:1)

您需要考虑可以从try块中的方法抛出哪些异常,以及您可以在当前抽象级别处理哪些异常。

在您的情况下,我希望getFirstLineFromFile方法,例如,肯定会抛出您想要捕获的异常。现在,无论是包装和重新抛出异常,还是采取其他操作,都取决于您是否可以在此级别实际处理异常。考虑一下您可以回退的默认文件的情况 - 该方法可能只是记录警告并继续使用默认值。或者,如果整个应用程序基于读取用户提供的文件,那么这更可能是一个致命的异常,应该传播到顶层并传达给那里的用户。

没有像“永远投掷”或“永不投掷”这样的硬性规则;一般来说,我认为只要存在异常类型的情况而不应该被认为是方法的正常结果,就应该抛出异常,因此不能通过方法的返回类型充分描述。 (例如,返回布尔值的isValidDbUser方法可能只能SQLException处理return false;但返回int的getNumProductsRegisteredInDB几乎肯定会传播异常)。

答案 2 :(得分:0)

不要听那些会告诉你不应该在一个大块中遇到多个异常的人(成群)。在某些情况下,这是一种完全合理的方式来执行常规错误处理,这就是为什么在语言中存在这样做的能力。

有一些例外,您可以做一些特定和有用的事情(即在catch块中从它们中恢复。)这些是您想要单独捕获的异常类型,并且尽可能接近它们发生的位置尽可能。

但是,您在现实生活中将面临的大多数例外将是完全意外的,未经检查的例外。它们是程序员错误(错误),断言失败,硬件故障,网络连接断开等的结果。

您应该通过指定特定的“阻塞点”来防御性地设计您的软件,以处理这些不可预测的异常,同时最大限度地减少对应用程序其余部分的干扰。 (请记住,在许多情况下,“处理”异常通常只是意味着中止当前操作并记录错误或以其他方式告诉用户发生了意外错误。)

因此,例如,如果您的程序将文件保存到磁盘,您可以将整个保存操作包装在try块中以捕获保存期间出错的内容:

try {
   // attempt to perform the save operation
   doSave();

} catch (Throwable t) {
   // tell the user that the save failed for unexpected reasons
   // and log the error somewhere
   informUser("save failed!");
   log("save failed!", t);

} finally {
   // last minute cleanup (happens whether save succeeded or failed)
   ...
}

请注意,我们在这里选择了一个不错的阻塞点方法(doSave()),然后阻止任何意外的错误冒泡而不是这一点。阻塞点表示单个可取消的操作(保存)。虽然如果你遇到意外的异常,这个操作显然是敬酒,但无论在阻塞点的另一端发生什么,应用程序的其余部分都将保持良好状态。

另请注意,这个习惯用法不会阻止你在doSave()某处进一步处理你的一些异常。因此,如果存在可以从中恢复的异常,或者您希望以特殊方式处理的异常,请继续在doSave()中执行此操作。但对于其他一切,你有你的阻塞点。

您甚至可能希望在main方法中为整个程序设置一般的未捕获异常处理程序:

public static void main(String [] args) {
    try {
       startApplication();
    } catch (Throwable t) {
       informUser("unexpected error! quitting application");
       log("fatal application error", t);
    }

但是,如果你明智地设置了其他阻塞点,那么到目前为止没有任何例外情况会出现。如果要完成常规错误处理,还可以创建UncaughtExceptionHandler到重要线程,如果使用Swing,则包括主线程或AWT线程。


TL; DR;不要相信你应该尽可能具体地捕捉异常的教条。有时你想要捕获和处理特定的异常,有时你想使用阻塞点来捕获和处理“可能出错的任何其他东西”。