3 回答

TA貢獻1877條經驗 獲得超1個贊
Throwable.printStackTrace()將堆棧跟蹤寫入System.errPrintStream。System.err可以通過以下方式重定向JVM流程的流和基礎標準“錯誤”輸出流:
調用System.setErr()會更改所指向的目的地System.err。
或通過重定向流程的錯誤輸出流。錯誤輸出流可以重定向到文件/設備
人員可能會忽略其內容,
文件/設備可能無法進行日志輪換,這意味著在歸檔文件/設備的現有內容之前,需要重新啟動進程才能關閉打開的文件/設備句柄。
或文件/設備實際上丟棄所有寫入其中的數據,例如的情況/dev/null。
從以上推斷,調用僅Throwable.printStackTrace()構成有效的(不好/很好的)異常處理行為
如果您System.err在應用程序的整個生命周期中都沒有被重新分配,
如果您在應用程序運行時不需要輪換日志,
并且是否接受/設計了應用程序的日志記錄實踐System.err(包括JVM的標準錯誤輸出流)。
在大多數情況下,不滿足上述條件。一個人可能不知道JVM中正在運行的其他代碼,并且一個人無法預測日志文件的大小或進程的運行時間,因此,精心設計的日志記錄實踐將圍繞編寫“機器可解析的”日志文件(記錄器中的首選功能),以幫助支持。
最后,應該記住,的輸出Throwable.printStackTrace()肯定會與寫入的其他內容交織在一起System.err(甚至System.out可能兩者都重定向到相同的文件/設備)。這是一個必須處理的煩惱(對于單線程應用程序),因為在此類事件中不容易解析異常周圍的數據。更糟糕的是,多線程應用程序很可能會生成非?;靵y的日志,因為Throwable.printStackTrace() 它不是線程安全的。
沒有同步機制可以將堆棧跟蹤的寫入與System.err多個線程同時調用Throwable.printStackTrace()時的同步。要解決此問題,實際上需要您的代碼在與之關聯的監視器上進行同步System.err(System.out如果目標文件/設備相同,則還要進行同步),這對于支付日志文件的完整性來說是一筆不菲的代價。舉一個例子,ConsoleHandlerand StreamHandler類負責在java.util.logging; 提供的日志記錄工具中將日志記錄追加到控制臺。發布日志記錄的實際操作是同步的-每個嘗試發布日志記錄的線程也必須獲得與該日志記錄關聯的監視器上的鎖StreamHandler實例。如果希望使用System.out/ 保證具有非交錯日志記錄System.err,則必須確保相同-消息以可序列化的方式發布到這些流中。
考慮到以上所有內容以及在Throwable.printStackTrace()實際中非常有用的非常受限的場景,通常會發現調用它是一種不好的做法。
擴展前面段落之一中的參數,Throwable.printStackTrace與寫入控制臺的記錄器結合使用也是一個糟糕的選擇。部分原因是由于記錄器將在另一個監視器上進行同步,而您的應用程序(可能,如果您不需要交錯的日志記錄)將在另一個監視器上進行同步。當您在應用程序中使用兩個寫入相同目的地的不同記錄器時,該參數也適用。

TA貢獻1824條經驗 獲得超8個贊
打印異常本身的堆棧跟蹤并不構成壞習慣,但僅在發生異常時才打印stace跟蹤可能是這里的問題-通常,僅打印堆棧跟蹤是不夠的。
此外,如果在一個catch塊中執行的所有操作都是a,則有一種可能會懷疑未執行適當的異常處理e.printStackTrace。處理不當可能最多意味著問題會被忽略,最糟糕的是程序會在未定義或意外的狀態下繼續執行。
例
讓我們考慮以下示例:
try {
initializeState();
} catch (TheSkyIsFallingEndOfTheWorldException e) {
e.printStackTrace();
}
continueProcessingAssumingThatTheStateIsCorrect();
在這里,我們要進行一些初始化處理,然后再繼續進行一些需要進行初始化的處理。
在上面的代碼中,應該已經捕獲了異常并對其進行了適當的處理,以防止程序繼續使用continueProcessingAssumingThatTheStateIsCorrect我們認為可能會引起問題的方法。
在許多情況下,e.printStackTrace()這表明某些異常正在被吞噬,并且允許進行處理,就好像每個問題都沒有發生一樣。
為什么這會成為問題?
糟糕的異常處理變得更加普遍的最大原因之一可能是由于Eclipse之類的IDE如何自動生成e.printStackTrace對異常處理執行代碼的代碼:
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
(以上是try-catchEclipse自動生成的實際值,用于處理InterruptedException拋出的異常Thread.sleep。)
對于大多數應用程序,僅將堆棧跟蹤信息打印為標準錯誤可能還不夠。在許多情況下,不正確的異常處理可能導致應用程序以意外狀態運行,并可能導致意外和未定義的行為。
添加回答
舉報