Java - 抛出异常和捕获并重新抛出异常的区别

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

这是为了保留错误信息的堆栈跟踪吗?我尝试设置了一个示例,但是在这两个之间没有看到任何不同的输出。
感谢您的帮助。
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);
    }
}

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


3

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

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

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

有时候,如果somePieceOfCode抛出了一些不具有共同基类(除了Exception)但需要以相同方式处理的已检查异常,那么就会这样做。您可能不想仅仅捕获Exception,因为那样也会捕获像NullPointerException这样的东西,您可能更喜欢这些异常原样上升。
这段代码将让所有RuntimeExceptions向上冒泡,但处理所有其他异常。
这个习惯用法有点不寻常,不是每个人都喜欢,但您可能会在某些地方看到它。

1

采用这种方法,您可以修改异常。例如,您可以为其提供更具体的消息。

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

  • 它会使您的代码变得混乱,而没有额外的好处(在正常情况下)
  • 只有在必要时才应使用try-catch块,因为它可能会减慢执行速度

1

捕获并重新抛出异常的标准原因包括:

  1. 记录事件和异常。
  2. 由于异常而进行一些清理工作(但通常最好在finally块中完成)。
  3. 将异常包装在更合适的异常中(例如,对于您的processAccount()方法,抛出一个AccountException(或类似异常)可能更合适,而不是DbException)。

0

没有区别,除非你想在重新抛出异常之前对其进行操作。


0

我认为两者之间没有太大的区别,但就个人而言,我更喜欢第一个。

除非你能够处理异常或者你的类是一个边界,超出该边界不应该传播任何异常(例如,一个捕获所有异常并将用户路由到友好错误页面的Web控制器),否则你不应该捕获异常。

简单地捕获和重新抛出异常是浪费时间的。它不添加任何信息,也没有做任何有益的事情。

唯一的例外是捕获已检查的异常并将其包装为未检查的异常。否则,请避免使用第二种习惯用法。


0

捕获并重新抛出的主要好处之一是将异常包装在另一个特定领域的异常中,这样调用代码就不必担心实现相关问题,而只需捕获库特定的异常。

你给出的示例没有真正的好处,但是其他类库中可以看到这种好处的很好的例子-例如我们可以看看Hibernate。

Hibernate捕获通用的SQLException,然后检查对象以确定异常的真实原因,然后将其包装在更具描述性的Hibernate特定异常中,以便更好地说明问题的本质。

然而,如果您只是捕获异常并抛出相同的异常,则最有可能是为了首先记录异常(尽管这不一定是最佳方法)。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接