解析Java異常的棧軌跡及其相關(guān)方法
一.打印棧軌跡的方法
主動(dòng)調(diào)用Throwable對(duì)象的printStackTrace()=printStackTrace(System.err),printStackTrace(PrintStream),printStackTrace(PrintWriter)中的其中一個(gè)。
如果一個(gè)Exception沒(méi)有被處理,直接在main方法后面throws,程序退出前將調(diào)用異常的printStackTrace()方法,最終是Exception in thread "main" + printStackTrace()
二.棧軌跡
1、printStackTrace()
首先需要明確,這個(gè)方法并不是來(lái)自于Exception類(lèi)。Exception類(lèi)本身除了定義了幾個(gè)構(gòu)造器之外,所有的方法都是從其父類(lèi)繼承過(guò)來(lái)的。而和異常相關(guān)的方法都是從java.lang.Throwable類(lèi)繼承過(guò)來(lái)的。而printStackTrace()就是其中一個(gè)。
這個(gè)方法會(huì)將Throwable對(duì)象的棧軌跡信息打印到標(biāo)準(zhǔn)錯(cuò)誤輸出流上。輸出的大體樣子如下:
java.lang.NullPointerException
at MyClass.mash(MyClass.java:9)
at MyClass.crunch(MyClass.java:6)
at MyClass.main(MyClass.java:3)
輸出的第一行是toString()方法的輸出,后面幾行的內(nèi)容都是之前通過(guò)fillInStackTrace()方法保存的內(nèi)容。關(guān)于這個(gè)方法,我們后面會(huì)講。
下面看一個(gè)例子:
public class TestPrintStackTrace {
public static void f() throws Exception{
throw new Exception("出問(wèn)題啦!");
}
public static void g() throws Exception{
f();
}
public static void main(String[] args) {
try {
g();
}catch(Exception e) {
e.printStackTrace();
}
}
}
這個(gè)例子的輸出如下:
java.lang.Exception: 出問(wèn)題啦! at TestPrintStackTrace.f(TestPrintStackTrace.java:3) at TestPrintStackTrace.g(TestPrintStackTrace.java:6) at TestPrintStackTrace.main(TestPrintStackTrace.java:10)
在這個(gè)例子中,在方法f()中拋出異常,方法g()中調(diào)用方法f(),在main方法中捕獲異常,并且打印棧軌跡信息。因此,輸出依次展示了f—>g—>main的過(guò)程。
2、getStackTrace()方法
這個(gè)方法提供了對(duì)printStackTrace()方法所打印信息的編程訪問(wèn)。它會(huì)返回一個(gè)棧軌跡元素的數(shù)組。以上面的輸出為例,輸出的第2-4行每一行的內(nèi)容對(duì)應(yīng)一個(gè)棧軌跡元素。將這些棧軌跡元素保存在一個(gè)數(shù)組中。每個(gè)元素對(duì)應(yīng)棧的一個(gè)棧幀。數(shù)組的第一個(gè)元素保存的是棧頂元素,也就是上面的f。最后一個(gè)元素保存的棧底元素。
下面是一個(gè)使用getStackTrace()訪問(wèn)這些軌跡棧元素并打印輸出的例子:
public class TestPrintStackTrace {
public static void f() throws Exception{
throw new Exception("出問(wèn)題啦!");
}
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: 出問(wèn)題啦! 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()方法將返回一個(gè)Throwable對(duì)象,它是通過(guò)把當(dāng)前調(diào)用棧信息填入原來(lái)那個(gè)異常對(duì)象兒建立的,所以返回的還是原來(lái)的異常。
調(diào)用此方法的那一行將成為異常新的發(fā)生地,有關(guān)原來(lái)異常發(fā)生點(diǎn)的信息會(huì)丟失。它的效果等價(jià)于捕獲一個(gè)異常后,重新拋出另外一種異常。兩者不同的是,fillInStackTrace后的異常還是原來(lái)的異常(只是少了棧軌跡而已);而重新拋出一個(gè)異常的話,完全跟原異常信息無(wú)關(guān)了(當(dāng)然也沒(méi)有棧軌跡)。
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本身的信息,控制臺(tái)第一行打印的就是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)
- java編程之單元測(cè)試(Junit)實(shí)例分析(附實(shí)例源碼)
- 解析Java中所有錯(cuò)誤和異常的父類(lèi)java.lang.Throwable
- 淺析Java Web錯(cuò)誤/異常處理頁(yè)面
- Java異常處理實(shí)例教程
- 剖析Java中的事件處理與異常處理機(jī)制
- 總結(jié)Java的Struts框架的異常處理方法
- Java異常處理中的一些特殊情況舉例
- Java異常處理中同時(shí)有finally和return語(yǔ)句的執(zhí)行問(wèn)題
- Java異常處理之try...catch...語(yǔ)句的使用進(jìn)階
- Java中的異常測(cè)試框架JUnit使用上手指南
相關(guān)文章
關(guān)于pytorch相關(guān)部分矩陣變換函數(shù)的問(wèn)題分析
這篇文章主要介紹了pytorch相關(guān)部分矩陣變換函數(shù),包括tensor維度順序變換BCHW順序的調(diào)整,矩陣乘法相關(guān)函數(shù),矩陣乘,點(diǎn)乘,求取矩陣對(duì)角線元素或非對(duì)角線元素的問(wèn)題,本文給大家介紹的非常詳細(xì),需要的朋友可以參考下2022-03-03
詳解Java合并數(shù)組的兩種實(shí)現(xiàn)方式
這篇文章主要介紹了Java合并數(shù)組的兩種實(shí)現(xiàn)方式,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2019-04-04
Java深入講解instanceof關(guān)鍵字的使用
instanceof 是 Java 的一個(gè)二元操作符,類(lèi)似于 ==,>,< 等操作符。instanceof 是 Java 的保留關(guān)鍵字。它的作用是測(cè)試它左邊的對(duì)象是否是它右邊的類(lèi)的實(shí)例,返回 boolean 的數(shù)據(jù)類(lèi)型2022-05-05
SpringBoot數(shù)據(jù)訪問(wèn)的實(shí)現(xiàn)
本文主要介紹了SpringBoot數(shù)據(jù)訪問(wèn)的實(shí)現(xiàn),引入各種xxxTemplate,xxxRepository來(lái)簡(jiǎn)化我們對(duì)數(shù)據(jù)訪問(wèn)層的操作,感興趣的可以了解一下2023-11-11
java IO流將一個(gè)文件拆分為多個(gè)子文件代碼示例
這篇文章主要介紹了java IO流將一個(gè)文件拆分為多個(gè)子文件代碼示例,具有一定借鑒價(jià)值,需要的朋友可以參考下。2017-12-12
spring-boot2.7.8添加swagger的案例詳解
這篇文章主要介紹了spring-boot2.7.8添加swagger的案例詳解,本文通過(guò)實(shí)例代碼給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友參考下吧2024-01-01
Java自定義一個(gè)變長(zhǎng)數(shù)組的思路與代碼
有時(shí)我們希望將把數(shù)據(jù)保存在單個(gè)連續(xù)的數(shù)組中,以便快速、便捷地訪問(wèn)數(shù)據(jù),但這需要調(diào)整數(shù)組大小或者對(duì)其擴(kuò)展,下面這篇文章主要給大家介紹了關(guān)于Java自定義一個(gè)變長(zhǎng)數(shù)組的思路與代碼,需要的朋友可以參考下2022-12-12
springboot創(chuàng)建多module項(xiàng)目的實(shí)例
這篇文章主要介紹了springboot創(chuàng)建多module項(xiàng)目的實(shí)例代碼,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2022-02-02
SpringBoot詳解如何實(shí)現(xiàn)讀寫(xiě)分離
當(dāng)響應(yīng)的瓶頸在數(shù)據(jù)庫(kù)的時(shí)候,就要考慮數(shù)據(jù)庫(kù)的讀寫(xiě)分離,當(dāng)然還可以分庫(kù)分表,那是單表數(shù)據(jù)量特別大,當(dāng)單表數(shù)據(jù)量不是特別大,但是請(qǐng)求量比較大的時(shí)候,就要考慮讀寫(xiě)分離了.具體的話,還是要看自己的業(yè)務(wù)...如果還是很慢,那就要分庫(kù)分表了...我們這篇就簡(jiǎn)單講一下讀寫(xiě)分離2022-05-05

