解析Java異常的棧軌跡及其相關(guān)方法
一.打印棧軌跡的方法
主動調(diào)用Throwable對象的printStackTrace()=printStackTrace(System.err),printStackTrace(PrintStream),printStackTrace(PrintWriter)中的其中一個。
如果一個Exception沒有被處理,直接在main方法后面throws,程序退出前將調(diào)用異常的printStackTrace()方法,最終是Exception in thread "main" + printStackTrace()
二.棧軌跡
1、printStackTrace()
首先需要明確,這個方法并不是來自于Exception類。Exception類本身除了定義了幾個構(gòu)造器之外,所有的方法都是從其父類繼承過來的。而和異常相關(guān)的方法都是從java.lang.Throwable類繼承過來的。而printStackTrace()就是其中一個。
這個方法會將Throwable對象的棧軌跡信息打印到標準錯誤輸出流上。輸出的大體樣子如下:
java.lang.NullPointerException
at MyClass.mash(MyClass.java:9)
at MyClass.crunch(MyClass.java:6)
at MyClass.main(MyClass.java:3)
輸出的第一行是toString()方法的輸出,后面幾行的內(nèi)容都是之前通過fillInStackTrace()方法保存的內(nèi)容。關(guān)于這個方法,我們后面會講。
下面看一個例子:
public class TestPrintStackTrace {
public static void f() throws Exception{
throw new Exception("出問題啦!");
}
public static void g() throws Exception{
f();
}
public static void main(String[] args) {
try {
g();
}catch(Exception e) {
e.printStackTrace();
}
}
}
這個例子的輸出如下:
java.lang.Exception: 出問題啦! at TestPrintStackTrace.f(TestPrintStackTrace.java:3) at TestPrintStackTrace.g(TestPrintStackTrace.java:6) at TestPrintStackTrace.main(TestPrintStackTrace.java:10)
在這個例子中,在方法f()中拋出異常,方法g()中調(diào)用方法f(),在main方法中捕獲異常,并且打印棧軌跡信息。因此,輸出依次展示了f—>g—>main的過程。
2、getStackTrace()方法
這個方法提供了對printStackTrace()方法所打印信息的編程訪問。它會返回一個棧軌跡元素的數(shù)組。以上面的輸出為例,輸出的第2-4行每一行的內(nèi)容對應(yīng)一個棧軌跡元素。將這些棧軌跡元素保存在一個數(shù)組中。每個元素對應(yīng)棧的一個棧幀。數(shù)組的第一個元素保存的是棧頂元素,也就是上面的f。最后一個元素保存的棧底元素。
下面是一個使用getStackTrace()訪問這些軌跡棧元素并打印輸出的例子:
public class TestPrintStackTrace {
public static void f() throws Exception{
throw new Exception("出問題啦!");
}
public static void g() throws Exception{
f();
}
public static void main(String[] args) {
try {
g();
}catch(Exception e) {
e.printStackTrace();
System.out.println("------------------------------");
for(StackTraceElement elem : e.getStackTrace()) {
System.out.println(elem);
}
}
}
}
這樣的輸出和printStackTrace()的輸出基本上是一樣的,如下:
java.lang.Exception: 出問題啦! at TestPrintStackTrace.f(TestPrintStackTrace.java:3) at TestPrintStackTrace.g(TestPrintStackTrace.java:6) at TestPrintStackTrace.main(TestPrintStackTrace.java:10) TestPrintStackTrace.f(TestPrintStackTrace.java:3) TestPrintStackTrace.g(TestPrintStackTrace.java:6) TestPrintStackTrace.main(TestPrintStackTrace.java:10)
三.fillInStackTrace方法
native fillInStackTrace()方法將返回一個Throwable對象,它是通過把當前調(diào)用棧信息填入原來那個異常對象兒建立的,所以返回的還是原來的異常。
調(diào)用此方法的那一行將成為異常新的發(fā)生地,有關(guān)原來異常發(fā)生點的信息會丟失。它的效果等價于捕獲一個異常后,重新拋出另外一種異常。兩者不同的是,fillInStackTrace后的異常還是原來的異常(只是少了棧軌跡而已);而重新拋出一個異常的話,完全跟原異常信息無關(guān)了(當然也沒有棧軌跡)。
package com.jyz.study.jdk.exception;
/**
* 棧軌跡
* fillInStackTrace
* @author JoyoungZhang@gmail.com
*
*/
public class FillInStackTrace {
public static void main(String[] args) throws Exception {
test1();
}
private static void test1() throws Exception{
try{
test2();
}catch(NullPointerException ex){
//1 throw (Exception)ex.fillInStackTrace();
//2 throw new Exception();
}
}
private static void test2(){
test3();
}
private static void test3(){
throw new NullPointerException("str is null");
}
}
1和2的異常棧信息均如圖:

不同的是this本身的信息,控制臺第一行打印的就是this。
1的棧信息
Exception in thread "main" java.lang.NullPointerException: str is null at com.jyz.study.jdk.exception.FillInStackTrace.test1(FillInStackTrace.java:20) at com.jyz.study.jdk.exception.FillInStackTrace.main(FillInStackTrace.java:13)
2的棧信息
Exception in thread "main" java.lang.Exception at com.jyz.study.jdk.exception.FillInStackTrace.test1(FillInStackTrace.java:21) at com.jyz.study.jdk.exception.FillInStackTrace.main(FillInStackTrace.java:13)
相關(guān)文章
關(guān)于pytorch相關(guān)部分矩陣變換函數(shù)的問題分析
這篇文章主要介紹了pytorch相關(guān)部分矩陣變換函數(shù),包括tensor維度順序變換BCHW順序的調(diào)整,矩陣乘法相關(guān)函數(shù),矩陣乘,點乘,求取矩陣對角線元素或非對角線元素的問題,本文給大家介紹的非常詳細,需要的朋友可以參考下2022-03-03
Java深入講解instanceof關(guān)鍵字的使用
instanceof 是 Java 的一個二元操作符,類似于 ==,>,< 等操作符。instanceof 是 Java 的保留關(guān)鍵字。它的作用是測試它左邊的對象是否是它右邊的類的實例,返回 boolean 的數(shù)據(jù)類型2022-05-05
SpringBoot數(shù)據(jù)訪問的實現(xiàn)
本文主要介紹了SpringBoot數(shù)據(jù)訪問的實現(xiàn),引入各種xxxTemplate,xxxRepository來簡化我們對數(shù)據(jù)訪問層的操作,感興趣的可以了解一下2023-11-11
spring-boot2.7.8添加swagger的案例詳解
這篇文章主要介紹了spring-boot2.7.8添加swagger的案例詳解,本文通過實例代碼給大家介紹的非常詳細,對大家的學(xué)習(xí)或工作具有一定的參考借鑒價值,需要的朋友參考下吧2024-01-01
springboot創(chuàng)建多module項目的實例
這篇文章主要介紹了springboot創(chuàng)建多module項目的實例代碼,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教2022-02-02

