3

当在下面的代码中重新抛出异常时,不会保留原始堆栈跟踪。

异常在第 148 行抛出并在第 150 行重新抛出。在重新抛出后第 150 行是指定的异常源。

我必须怎么做才能保留原始堆栈跟踪?

代码:

    try {

        content = (InputStream) conn.getContent(); //line 148

    } catch (IOException e) {

        throw new RuntimeException(e); //line 150

    }

原始堆栈跟踪:

 (java.lang.StackTraceElement[]) [sun.net.www.protocol.http.HttpURLConnection.getInputStream(Unknown Source), java.net.URLConnection.getContent(Unknown Source), com.mycompany.myapp.client.services.impl.AbstractClientService.getResponseEle(AbstractClientService.java:148), com.mycompany.myapp.client.services.impl.AbstractClientService.getResponseEleWithCheck(AbstractClientService.java:162), com.mycompany.myapp.client.services.impl.AbstractClientService.getResponseEleWithCheck(AbstractClientService.java:158), com.mycompany.myapp.client.services.impl.InfoQueryClientServiceImpl.getFileOnTmpList(InfoQueryClientServiceImpl.java:84), com.mycompany.myapp.client.myappClient.getFileOnTmpList(myappClient.java:196), com.mycompany.myapp.client.model.Model.updateStudyInfos(Model.java:96), com.mycompany.myapp.client.model.Model.instantiateSingleton(Model.java:46), com.mycompany.myapp.applet.MainApplet.addMainPanel(MainApplet.java:106), com.mycompany.myapp.applet.MainApplet.createUIPanel(MainApplet.java:76), com.mycompany.myapp.applet.MainApplet.init(MainApplet.java:58), com.sun.deploy.uitoolkit.impl.awt.AWTAppletAdapter.init(Unknown Source), sun.plugin2.applet.Plugin2Manager$AppletExecutionRunnable.run(Unknown Source), java.lang.Thread.run(Unknown Source)]

重新抛出后的堆栈跟踪:

 (java.lang.StackTraceElement[]) [com.mycompany.myapp.client.services.impl.AbstractClientService.getResponseEle(AbstractClientService.java:150), com.mycompany.myapp.client.services.impl.AbstractClientService.getResponseEleWithCheck(AbstractClientService.java:162), com.mycompany.myapp.client.services.impl.AbstractClientService.getResponseEleWithCheck(AbstractClientService.java:158), com.mycompany.myapp.client.services.impl.InfoQueryClientServiceImpl.getFileOnTmpList(InfoQueryClientServiceImpl.java:84), com.mycompany.myapp.client.myappClient.getFileOnTmpList(myappClient.java:196), com.mycompany.myapp.client.model.Model.updateStudyInfos(Model.java:96), com.mycompany.myapp.client.model.Model.instantiateSingleton(Model.java:46), com.mycompany.myapp.applet.MainApplet.addMainPanel(MainApplet.java:106), com.mycompany.myapp.applet.MainApplet.createUIPanel(MainApplet.java:76), com.mycompany.myapp.applet.MainApplet.init(MainApplet.java:58), com.sun.deploy.uitoolkit.impl.awt.AWTAppletAdapter.init(Unknown Source), sun.plugin2.applet.Plugin2Manager$AppletExecutionRunnable.run(Unknown Source), java.lang.Thread.run(Unknown Source)] 
4

5 回答 5

3

您的代码不会重新抛出原始异常,而是抛出新实例,RuntimeException该实例的堆栈跟踪在创建时已填充。

您可以在捕获 RuntimeException 时进行以太调用Throwable.getCause().getStackTrace(),或者在抛出 RuntimeException 之前将 RuntimeException 的堆栈跟踪设置为原始异常之一。

于 2012-11-15T10:51:43.983 回答
2

“问题”是您没有重新抛出异常。相反,您正在抛出一个的异常。如果你真的重新抛出这样的异常:

try {
    content = (InputStream) conn.getContent();
} catch (IOException e) {
    throw e;
}

你会发现堆栈跟踪被保留了。

如果您Throwable.printStackTrace()在现代 JVM 上使用,它将显示链接异常及其(唯一)堆栈帧。换句话说,原始异常的信息被保留。


有一种方法可以将堆栈跟踪从一个异常拼接到另一个异常中。

try {
    content = (InputStream) conn.getContent();
} catch (IOException e) {
    RuntimeException re = new RuntimeException(e);
    re.setStackTrace(e.getStackTrace());
    throw re;
}

但是,我个人认为这不是一个好主意。虽然 的行号RuntimeException现在与原始异常相同,但您会发现连接对象的异常情况似乎抛出了RuntimeException代码表明这不可能发生的地方。我认为最好以正常方式链接异常并让程序员正确读取链接异常的堆栈跟踪。

于 2012-11-15T10:43:13.460 回答
0

堆栈跟踪被保留。

您必须从那里获取原因RuntimeException并从那里获取堆栈跟踪以获取来源。

此功能称为异常链接。

于 2012-11-15T10:41:51.873 回答
0

您必须按照导致 Throwables 的参考来获取原始堆栈跟踪。例如

public static StackTraceElement[] getCausingStacktrace(Throwable throwable) {
  if (throwable == null) {
    throw new NullPointerException();
  }
  while (throwable != null) {
    throwable = throwable.getCause();
  }
  return throwable.getStacktrace();
}
于 2014-11-22T11:20:06.360 回答
0

如果您只想要原始堆栈跟踪,请不要抓住它。另一方面,我假设您出于某种原因将其包装在运行时异常中。您可以使用从运行时异常中获取原始异常getCause()

于 2012-11-15T10:40:48.723 回答