5

我对捕获和重新抛出异常而不是首先抛出异常的好处感到困惑。

例如

private void testMethod() throws Exception
{
    //some bad code here
} 

相对:

private void testMethod() throws Exception
{
    try
    {
        //some bad code here
    }
    catch (Exception e)
    {
        throw e;
    }
} //end testMethod()

这是为了保留错误消息的堆栈跟踪吗?我尝试设置一个示例,但没有看到两者之间有任何不同的输出。

谢谢您的帮助。

4

7 回答 7

6

您的两个代码示例之间的行为没有区别。(特别是,堆栈跟踪是在创建异常时记录的,而不是在抛出异常时记录的,因此重新抛出的异常仍将具有原始堆栈跟踪)。通常,人们因此使用更简单的成语。

这并不是说重新抛出没有它的用​​途。例如,如果您想处理除 FooBarExceptions 之外的所有异常,您可以编写:

try {
    // bad code 
} catch (FooBarException e) {
    throw e;
} catch (Exception e) {
    e.printStackTrace();
}

或者,如果处理异常的决定比简单地检查其类型更复杂,您可以简单地捕获它,如果事实证明您无法处理它,则重新抛出:

for (int attempts = 0; attemps < 6; attempts++) {
    try {
        return crankyMethod();
    } catch (Exception e) {
        if (fatal(e)) {
            throw e;
        } else {
            // try again
            continue;
        }
    }
}

值得注意的是,当人们说 rethrow 时,有些人的意思是抛出不同的异常,如下例所示:

for (int i = 0; i < array.length; i++) {
    try {
        process(array[i]);
    } catch (Exception e) {
        throw new RuntimeException("Could not process element at index " + i, e);
    }
}

这种模式的优点是用可能相关的附加信息来装饰原始异常(在上面的示例中:无法处理哪些数据)。请注意,原始异常被传递给新异常的构造函数,因此它的堆栈跟踪不会丢失。

于 2012-03-08T01:36:41.743 回答
3

正如其他人所说,在您的示例中没有区别,应避免使用第二种形式。

有时唯一有意义的地方是您需要捕获一些异常,并让其他异常向上抛出。因为 Java 的异常处理语法是有限的,有时你可能会这样做:

try {
   somePieceOfCode();
} catch( RuntimeException e ) {
   throw e;
} catch( Exception e ) {
   handleException(e);
}

如果somePieceOfCode抛出许多没有公共基类(除了Exception)但需要以相同方式处理的不同检查异常,有时会这样做。您可能不想只捕获Exception,因为这也会捕获诸如 之类的东西NullPointerException,并且您可能更喜欢这些异常按原样冒泡。

此代码将让所有RuntimeExceptions冒泡向上,但处理所有其他异常。

这个成语有点不寻常,并不是每个人都喜欢它,但你可能会在某些地方看到它。

于 2012-03-08T01:16:19.160 回答
1

捕获和重新抛出异常的标准原因是:

  1. 记录事件和异常。
  2. 由于异常进行一些清理(但通常最好在 finally 块中完成)。
  3. 将异常包装在更合适的异常中(即,您的 processAccount() 方法可能更适合抛出 AccountException(或类似的)而不是 DbException)。
于 2012-03-08T01:11:39.060 回答
1

使用这种方法,您可以修改异常。例如,您可以给它一个更具体的消息。

话虽如此,您通常不应该使用这种技术,因为

  • 它聚集你的代码没有额外的好处(在正常情况下)
  • 您应该只在实际需要时使用 try-catch 块,因为它会减慢执行速度
于 2012-03-08T01:10:41.690 回答
0

捕获然后重新抛出的主要好处之一是将异常包装在另一个特定于域的异常中,因此调用代码不必担心特定于实现的问题,并且可以捕获特定于库的异常。

在您给出的示例中没有真正的好处,但是在其他库中可以看到这种好处的一个很好的例子——作为一个例子,我们可以看看 Hibernate。

Hibernate 捕获一般的 SQLException,然后检查对象以确定异常的真正原因,然后将其包装在 Hibernate 特定的异常中,该异常更能描述问题所在。

但是,如果您只是捕获一个异常并抛出相同的异常,那么您很可能会这样做,以便您可以首先记录异常(尽管这不一定是最好的使用方法)。

于 2012-03-08T01:18:37.123 回答
0

没有区别。除非您想在重新抛出它之前对其进行处理(例外)。

于 2012-03-08T00:59:12.343 回答
0

我不认为有太大的区别,但是对于它的价值,我更喜欢第一个。

你不应该捕获一个异常,除非你能对它做点什么,或者如果你的类是一个异常不应该传播的边界(例如,一个捕获所有异常的 web 控制器并将用户路由到友好的错误页面)。

简单地捕捉和重新抛出是对击键的浪费。它没有添加任何信息,也没有做任何建设性的事情。

一个例外是捕获已检查的异常并将其包装为未检查的异常。否则避免使用第二个成语。

于 2012-03-08T00:59:40.633 回答