在不丢失堆栈跟踪的情况下重新抛出Java中的异常


417

在C#中,我可以使用该throw;语句在保留堆栈跟踪的同时重新引发异常:

try
{
   ...
}
catch (Exception e)
{
   if (e is FooException)
     throw;
}

Java中是否有类似的东西(不会丢失原始堆栈跟踪)?


4
您为什么认为它会失去原始的堆栈跟踪?抛出新的SomeOtherException并忘记在构造函数或initCause()中分配根本原因时,松开它的唯一方法。
akarnokd

4
我相信这是.Net中代码的行为方式,但我不再乐观了。可能值得在某个地方查找它或进行一次小型测试。
ripper234 2009年

11
Throwables不会因为抛出它们而被修改。要更新堆栈跟踪,您必须调用fillInStackTrace()。方便地,此方法在的构造函数中调用Throwable
罗伯特

50
在C#中,是的,throw e;将丢失stacktrace。但不是用Java。
Tim Goodman 2013年

Answers:


560
catch (WhateverException e) {
    throw e;
}

只会简单地抛出您捕获的异常(显然,周围的方法必须通过其签名等方式允许此操作)。该异常将保留原始堆栈跟踪。


4
嗨,当我添加throw e行时,InterruptedException e给出了未处理的Exception消息。如果将其替换为更广泛的Exception e,则不是这样。应该如何正确地做到这一点?
James P.

1
@James,我只是观察到如果在函数声明中添加“ throws XxxException”,则消息消失。
shiouming 2012年

2
在Java 7编译器中,这种重新抛出更为智能。现在,它可以与包含方法中的特定“抛出”异常一起正常工作。
WaldemarWosiński2013年

193
@James如果您catch(Exception e) { throw e; }将无法处理。如果您catch(InterruptedException ie) { throw ie; }将处理。根据经验,不要catch(Exception e)-这不是口袋妖怪,我们也不想全部捉住它们!
corsiKa 2013年

3
@corsiKa不一定要“全部抓住”,这只是一个不同的用例。如果您有一个顶级循环或事件处理程序(例如,在线程的运行中),但至少没有捕获RuntimeException并将其记录下来,那么您通常会完全错过该异常,并且在重要的循环中默默地中断通常是一次失败。对于不知道其他代码可能起作用或引发的插件功能,这也确实非常有用。对于像这样的自上而下的使用,捕获异常通常不仅是一个好主意,而且是一种最佳实践。
Bill

82

我会选择:

try
{
    ...
}
catch (FooException fe){
   throw fe;
}
catch (Exception e)
{
    // Note: don't catch all exceptions like this unless you know what you
    // are doing.
    ...
}

6
在Java中绝对适合捕获特定异常,而不是泛型和实例检查。+1
amischiefr

8
-1,因为除非您不知道自己在做什么,否则永远不要捕捉简单的“ Exception”。
Stroboskop,2009年

19
@Stroboskop:是的,但是要回答,最好使用与问题中相同的代码。
user85421

14
有时捕获所有异常是可以的。例如在编写测试用例时。或用于记录目的。或在主要地方,没有被抓住就意味着坠毁。
约翰·亨克尔

1
@JohnHenckel和其他人:有效点表示。我更新了问题以明确指出Exception,在大多数(但不是全部)情况下,捕获通常不是正确的选择。
Per Lundberg

74

您还可以将异常包装在另一个异常中,并通过将Exception作为Throwable作为cause参数传入来保留原始堆栈跟踪:

try
{
   ...
}
catch (Exception e)
{
     throw new YourOwnException(e);
}

8
我也建议您使用throw new YourOwnException("Error while trying to ....", e);
朱利安(Julien)

这就是我想要的,尤其是第一个评论的版本,您可以在其中传递您自己的信息
Csaba

这样可以正确显示错误消息,但是堆栈跟踪将错误行显示为“ throw new .......(e)”行,而不是引起异常的原始行。
阿什本RK

22

在Java中几乎是相同的:

try
{
   ...
}
catch (Exception e)
{
   if (e instanceof FooException)
     throw e;
}

5
不,只要您不实例化新的Exception对象,堆栈跟踪就保持不变。
Mnementh,2009年

28
我会为FooException添加特定的捕获
dfa

3
我同意这种特定情况,但是添加特定的捕获可能不是正确的选择-假设您对所有异常都有一些通用代码,然后针对特定异常将其重新抛出。
alves

1
@MarkusLausberg但是最后没有捕获异常。
罗伯特

是的,但这不是问题。
马库斯·劳斯伯格,2012年

14

在Java中,您只是抛出捕获的异常,throw e而不是throw。Java维护堆栈跟踪。


6

像这样的东西

try 
{
  ...
}
catch (FooException e) 
{
  throw e;
}
catch (Exception e)
{
  ...
}

5
public int read(byte[] a) throws IOException {
    try {
        return in.read(a);
    } catch (final Throwable t) {
        /* can do something here, like  in=null;  */
        throw t;
    }
}

这是一个具体的示例,其中方法抛出IOException。该final方法t只能保存从try块引发的异常。其他阅读材料可在此处此处找到。



3

如果将捕获到的兴奋剂包装到另一个异常中(以提供更多信息),或者只是重新抛出捕获到的兴奋剂,则会使用堆栈跟踪。

try{ ... }catch (FooException e){ throw new BarException("Some usefull info", e); }


2

我当时也遇到类似的情况,我的代码可能会引发许多我想重新抛出的异常。上面描述的解决方案不适用于我,因为Eclipse告诉我这throw e;导致了未处理的异常,所以我只是这样做了:

try
{
...
} catch (NoSuchMethodException | SecurityException | IllegalAccessException e) {                    
    throw new RuntimeException(e.getClass().getName() + ": " + e.getMessage() + "\n" + e.getStackTrace().toString());
}

为我工作.... :)

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.