在Java中重新触发异常而不丢失堆栈跟踪

在Java中重新触发异常而不丢失堆栈跟踪,java,exception,Java,Exception,在C#中,我可以使用抛出语句在保留堆栈跟踪的同时重新显示异常: try { ... } catch (Exception e) { if (e is FooException) throw; } Java中是否有类似的东西(不会丢失原始堆栈跟踪?在Java中几乎是一样的: try { ... } catch (Exception e) { if (e instanceof FooException) throw e; } 将简单地重新显示您捕获的异

在C#中,我可以使用
抛出语句在保留堆栈跟踪的同时重新显示异常:

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

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

在Java中几乎是一样的:

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

将简单地重新显示您捕获的异常(显然,周围的方法必须通过其签名等来允许)。异常将保留原始堆栈跟踪。

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

我更喜欢:

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

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

您还可以将异常包装到另一个异常中,并通过将异常作为可丢弃项作为原因参数传入来保留原始堆栈跟踪:

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

这是一个具体的示例,其中该方法抛出一个
IOException
final
表示
t
只能保存从try块抛出的异常。可以找到其他阅读材料,如果您将捕获的例外项包装到其他例外项中(以提供更多信息),或者如果您只是重新播放捕获的例外项,则会保留堆栈跟踪

试试看{
...
}捕获(FooE例外){
抛出新的异常(“一些有用的信息”,e);

}

我遇到了一个类似的情况,我的代码可能会抛出一些不同的异常,我只是想重新抛出这些异常。上面描述的解决方案对我不起作用,因为Eclipse告诉我,
throw e导致未处理的异常,所以我只做了以下操作:

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


为我工作……:)

我同意在这种情况下为FooException添加一个特定捕获,但添加一个特定捕获可能不是正确的选择-假设您有一些用于所有异常的通用代码,然后,对于一个特定的异常,重新调用它。@MarkusLausberg,但最终没有捕获异常。是的,但这不是问题所在。在Java中,捕获特定异常肯定比捕获泛型和检查实例更合适+1-1因为除非你知道自己在做什么,否则永远不应该捕捉到简单的“异常”。@Stroboskop:是的,但要回答这个问题,最好使用与问题相同(类似)的代码!有时捕获所有异常是可以的。例如,当您编写测试用例时。或用于日志记录目的。或者在主要情况下,不接球意味着撞车。@JohnHenckel和其他人:有效分数inded。我更新了这个问题,明确指出在大多数(但不是所有)情况下,捕获
异常
通常不是正确的做法。为什么您认为它会丢失原始堆栈跟踪?当您抛出新的SomeOtherException并忘记在构造函数或initCause()中指定根本原因时,唯一的方法就是释放它。我相信这就是代码在.Net中的行为方式,但我不再肯定。可能值得在某处查找或运行一个小测试。
Throwable
s不会因为抛出它们而被修改。要更新堆栈跟踪,必须调用
fillInStackTrace()
。方便地在
Throwable
的构造函数中调用此方法将丢失堆栈跟踪。但不是在Java中。Oracle的一些关于Java 7异常的文档:嗨,InterruptedException e在我添加throw e行时给出了一条未处理的异常消息。如果我用更广泛的例外e来代替它,情况就不是这样了。这应该如何正确地完成呢?在Java7中,用于这种重新调用的编译器更智能。现在它可以很好地处理containing方法中的特定“throws”异常。@James如果您
catch(Exception e){throw e;}
,它将被取消处理。如果您
catch(InterruptedException ie){throw ie;}
它将被处理。根据经验,不要捕捉(例外e)
-这不是口袋妖怪,我们不想捕捉它们@corsiKa你不想“抓住所有人”并不一定是真的,这只是一个不同的用例。如果您有一个顶级循环或事件处理程序(例如,在线程的运行中),如果您没有捕获至少一个RuntimeException并记录它,那么您通常会完全错过该异常,并悄悄地从一个重要的循环中跳出来,这通常是一次性的失败。对于那些你不知道其他代码会做什么或抛出什么的插件功能来说,它也是非常好的。。。对于像这样的自上而下的使用,捕获异常通常不仅是一个好主意,而且是一个最佳实践。@CorsiKa我提到它是因为我使用的应用程序有几个线程随机地吃掉异常。任何线程,你不想打破沉默,应该有一个捕捉异常在顶部,你可能会想,有很多开发人员不在你的确切情况-许多程序员使用线程,而不是所有使用框架来抽象他们-一些写自己的框架。它不一定是最终的。请参阅,我还建议您在旁边添加一条消息,使用
抛出新的YourOwnException(“尝试…时出错”,e)这是我一直在寻找的,尤其是第一条注释中的版本,您可以在其中传递自己的消息。这正确显示错误消息,但堆栈跟踪显示错误行为带有“throw new……(e)”的行,而不是导致异常的原始行。
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;
    }
}
try
{
...
} catch (NoSuchMethodException | SecurityException | IllegalAccessException e) {                    
    throw new RuntimeException(e.getClass().getName() + ": " + e.getMessage() + "\n" + e.getStackTrace().toString());
}