2012-11-15 27 views
3

在下面的代碼中重新拋出異常時,原始堆棧跟蹤不會保留。在java中重新拋出異常時堆棧跟蹤未得到充分維護

第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)] 
+0

您是否嘗試在RuntimeException上調用getCause()? –

回答

0

如果你只想要原來的堆棧跟蹤,不抓住它。另一方面,我假設你將其包裝在運行時異常中是有原因的。您可以使用getCause()

0

從運行異常中獲得原始異常。保留堆棧跟蹤。

你必須從RuntimeException得到原因,並從那裏獲取堆棧跟蹤以獲取原點。

此功能稱爲異常鏈。

1

「問題」是你沒有重新拋出異常。而是你拋出一個新的異常。如果你真的重新拋出這樣一個異常:

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,代碼表示這種情況不會發生。我認爲最好是以正常方式鏈接異常,並讓程序員正確讀取鏈式異常的堆棧跟蹤。

+0

這似乎是他試圖在未經檢查的異常中打包檢查的異常。我懷疑這會有所幫助。 – Dunes

+0

@Dunes - 我知道這一點。 –

3

您的代碼不會重新拋出原始異常,但將拋出新的實例RuntimeException,該實例的堆棧跟蹤已在創建點填充。

當您在執行RuntimeException之前捕獲RuntimeException或 時,您可以調用Throwable.getCause().getStackTrace()將RuntimeException的堆棧跟蹤設置爲原始異常的一個。

+0

什麼是最佳實踐? – user1826324

+0

由於除了拋出原始異常之外,你沒有在catch塊中做任何事情,所以最好的做法是不要在這裏捕獲它。如果您將它封裝在RuntimeException中以繞過定義檢查的異常,請將其添加爲原因。替換堆棧跟蹤仍然會導致信息丟失,因爲您只有堆棧跟蹤,而不是IOException。 – Janoz

+0

也許OP在運行時異常中包裝異常,以避免'污染'方法簽名和'throws'子句......? – monojohnny

0

你必須按照引起Throwables的參考來獲得原始堆棧跟蹤。例如

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