在java中重新抛出异常时,不会完全维护堆栈跟踪

时间:2012-11-15 10:38:17

标签: java java-ee exception-handling

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

在第148行&在第150行重新抛出。在Rethrowing之后,第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)] 

5 个答案:

答案 0 :(得分:3)

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

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

答案 1 :(得分:2)

“问题”是你不会重新抛出异常。而是你抛出一个新的异常。如果您确实重新抛出了这样的异常:

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

您会发现堆栈跟踪已保留。

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


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

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

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

答案 2 :(得分:0)

如果您只想要原始堆栈跟踪,请不要捕获它。另一方面,我假设您将其包装在运行时异常中是有原因的。您可以使用getCause()

从运行时异常中获取原始异常

答案 3 :(得分:0)

保留堆栈跟踪。

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

此功能称为异常链接。

答案 4 :(得分:0)

你必须遵循引起Throwables的引用来获得原始的堆栈跟踪。例如

public static StackTraceElement[] getCausingStacktrace(Throwable throwable) {
  if (throwable == null) {
    throw new NullPointerException();
  }
  while (throwable != null) {
    throwable = throwable.getCause();
  }
  return throwable.getStacktrace();
}