Java - 抛出异常与捕获和重新抛出异常之间的区别

时间:2012-03-08 00:56:49

标签: java exception try-catch throws

我很困惑抓住和重新抛出异常的好处,而不是把它放在首位。

例如

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()

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

感谢您的帮助。

7 个答案:

答案 0 :(得分:5)

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

这并不是说重新抛出没有它的用​​途。例如,如果你想处理除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;
        }
    }
}

值得注意的是,当人们说重新抛出时,有些人意味着抛出一个不同的异常,如下例所示:

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);
    }
}

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

答案 1 :(得分:2)

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

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

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

如果somePieceOfCode抛出许多不同的已检查异常但没有公共基类(Exception除外)但需要以相同方式处理,则有时会执行此操作。您可能不想仅仅抓住Exception,因为这也会抓住NullPointerException这样的内容,您可能更愿意将这些异常按原样冒出来。

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

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

答案 2 :(得分:1)

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

有了这个说法,你通常不应该使用这种技术,因为

  • 它集中了您的代码,没有额外的好处(在正常情况下)
  • 您应该只在实际需要的地方使用try-catch块,因为它可以减慢执行速度

答案 3 :(得分:1)

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

  1. 记录事件和例外情况。
  2. 由于异常而进行一些清理(但通常在finally块中做得更好)。
  3. 将异常包装在一个更合适的异常中(即,您的processAccount()方法可能更适合抛出AccountException(或某些此类)而不是DbException)。

答案 4 :(得分:0)

没有区别。除非你想在重新投掷它之前做一些事情(例外)。

答案 5 :(得分:0)

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

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

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

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

答案 6 :(得分:0)

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

在您给出的示例中没有任何实际好处,但是在其他库中可以看到这样一个好处的一个很好的例子 - 作为一个例子,我们可以看看Hibernate。

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

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