JDK源碼解析之 java.lang.Throwable

在 Java 中,所有的異常都有一個共同的祖先 Throwable(可拋出)。Throwable 指定代碼中可用異常傳播機制通過 Java 應用程序傳輸的任何問題的共性。

一、類定義

public class Throwable implements Serializable {}
  • Serializable:可被序列化的標志接口

二、成員變量

//靜態變量
//這兩個變量主要用于序列化
private static class SentinelHolder {public static final StackTraceElement STACK_TRACE_ELEMENT_SENTINEL =new StackTraceElement("", "", null, Integer.MIN_VALUE);public static final StackTraceElement[] STACK_TRACE_SENTINEL =new StackTraceElement[] {STACK_TRACE_ELEMENT_SENTINEL};
}
//一個空的StackTraceElement[]數組,用來初始化或者作為返回值。
private static final StackTraceElement[] UNASSIGNED_STACK = new StackTraceElement[0];
//一個空的只讀List,同樣用于初始化
private static final List<Throwable> SUPPRESSED_SENTINEL =Collections.unmodifiableList(new ArrayList<Throwable>(0));
//前兩個用于作為錯誤信息,后兩個作為printStackTrace方法的說明前綴使用
private static final String NULL_CAUSE_MESSAGE = "Cannot suppress a null exception.";
private static final String SELF_SUPPRESSION_MESSAGE = "Self-suppression not permitted";
private static final String CAUSE_CAPTION = "Caused by: ";
private static final String SUPPRESSED_CAPTION = "Suppressed: ";
//用作getSuppressed方法的返回值(當suppressedExceptions沒有元素時)
private static final Throwable[] EMPTY_THROWABLE_ARRAY = new Throwable[0];//實例變量
//用來保存棧信息的軌跡
private transient Object backtrace;	
//描述這個異常的信息
private String detailMessage;		
//描述這個異常由哪個Throwable導致,默認是this。
private Throwable cause = this;			
//異常拋出位置的棧信息,每個StackTraceElement代表一個棧信息,默認指向靜態常量UNASSIGNED_STACK,代表棧信息為空。
private StackTraceElement[] stackTrace = UNASSIGNED_STACK;		
//JDK 1.7引入的新特性。該List用來保存被屏蔽的異常對象,在try-catch語句中,如果try中拋出了異常,在執行流程轉移到方法棧上一層之前,finally語句塊會執行,但是,如果在finally語句塊中又拋出了一個異常,那么這個異常會覆蓋掉之前拋出的異常,這點很像finally中return的覆蓋。
private List<Throwable> suppressedExceptions = SUPPRESSED_SENTINEL;		

三、構造方法

public Throwable() {fillInStackTrace();
}
/*** @param message 異常描述信息,該參數直接賦值給實例變量detailMessage*/
public Throwable(String message) {fillInStackTrace();detailMessage = message;
}
/*** @param message 異常描述信息,該參數直接賦值給實例變量detailMessage* @param cause 描述當前異常由哪個異常引發*/
public Throwable(String message, Throwable cause) {fillInStackTrace();detailMessage = message;this.cause = cause;
}
/*** @param cause 描述當前異常由哪個異常引發*/
public Throwable(Throwable cause) {fillInStackTrace();detailMessage = (cause==null ? null : cause.toString());this.cause = cause;
}
/*** @param message 異常描述信息,該參數直接賦值給實例變量detailMessage* @param cause 描述當前異常由哪個異常引發* @param enableSuppression 是否支持Suppress異常消息* @param writableStackTrace 是否調用fillInStackTrace使堆棧信息可以寫入*/
protected Throwable(String message, Throwable cause,boolean enableSuppression, boolean writableStackTrace) {if (writableStackTrace) {fillInStackTrace();} else {stackTrace = null;}detailMessage = message;this.cause = cause;if (!enableSuppression)suppressedExceptions = null;
}

Throwable提供了4個public構造器和1個protected構造器(該構造器由JDK1.7引入)。4個public構造器共同點就是都調用了fillInStackTrace方法。

fillInStackTrace會首先判斷stackTrace是不是為null,如果不為null則會調用native方法fillInStackTrace獲取當前堆棧信息。那么什么時候為null呢,答案是上面的protected構造器可以指定writableStackTracefalse,這樣stackTrace就為null了,就不會調用fillInStackTrace獲取堆棧信息。如果你不需要異常的棧信息,你也可以重寫這個方法,讓它直接返回this,畢竟異常的爬棧是一個開銷比較大的操作。

四、常用方法

1、printStackTrace方法

printStackTrace把傳入的輸入流用內部類WrappedPrintStreamWrappedPrintWriter包裝,主要用來實現printStackTrace方法在打印堆棧信息時的線程安全。

public void printStackTrace() {printStackTrace(System.err);
}public void printStackTrace(PrintStream s) {printStackTrace(new WrappedPrintStream(s));
}public void printStackTrace(PrintWriter s) {printStackTrace(new WrappedPrintWriter(s));
}private void printStackTrace(PrintStreamOrWriter s) {Set<Throwable> dejaVu = Collections.newSetFromMap(new IdentityHashMap<Throwable, Boolean>());dejaVu.add(this);synchronized (s.lock()) {s.println(this);StackTraceElement[] trace = getOurStackTrace();for (StackTraceElement traceElement : trace)s.println("\tat " + traceElement);for (Throwable se : getSuppressed())se.printEnclosedStackTrace(s, trace, SUPPRESSED_CAPTION, "\t", dejaVu);Throwable ourCause = getCause();if (ourCause != null)ourCause.printEnclosedStackTrace(s, trace, CAUSE_CAPTION, "", dejaVu);}
}
}

printStackTrace把傳入的輸入流用內部類WrappedPrintStreamWrappedPrintWriter包裝,主要用來實現printStackTrace方法在打印堆棧信息時的線程安全。

2、getMessage()和getLocalizedMessage()

默認條件下可以調用getMessagegetLocalizedMessage方法獲取detailMessage

public String getMessage() {return detailMessage;
}
public String getLocalizedMessage() {return getMessage();
}

3、getCause()和initCause()

通過構造器自定義cause。構造完成后,可以通過getCause方法訪問獲取,如果沒有指定cause,則返回null

在構造完成后,也可通過initCause方法修改:修改cause的前提是必須在構造方法中沒有指定別的cause(即默認條件下causethis),否則會拋出IllegalStateException異常。另外也不能修改causethis

public synchronized Throwable getCause() {return (cause == this ? null : cause);
}public synchronized Throwable initCause(Throwable cause) {if (this.cause != this)throw new IllegalStateException("Can't overwrite cause with " +Objects.toString(cause, "a null"), this);if (cause == this)throw new IllegalArgumentException("Self-causation not permitted", this);this.cause = cause;return this;
}

五、拓展

1.處理異常機制

在 Java 應用程序中,異常處理機制為:拋出異常,捕捉異常。

拋出異常:當一個方法出現錯誤引發異常時,方法創建異常對象并交付運行時系統,異常對象中包含了異常類型和異常出現時的程序狀態等異常信息。運行時系統負責尋找處置異常的代碼并執行。throwsthrow

? 捕獲異常:在方法拋出異常之后,運行時系統將轉為尋找合適的異常處理器(exception handler)。潛在的異常處理器是異常發生時依次存留在調用棧中的方法的集合。當異常處理器所能處理的異常類型與方法拋出的異常類型相符時,即為合適 的異常處理器。運行時系統從發生異常的方法開始,依次回查調用棧中的方法,直至找到含有合適異常處理器的方法并執行。當運行時系統遍歷調用棧而未找到合適 的異常處理器,則運行時系統終止。同時,意味著Java程序的終止。try…catch

? 對于運行時異常、錯誤或可查異常,Java技術所要求的異常處理方式有所不同。

? 由于運行時異常的不可查性,為了更合理、更容易地實現應用程序,Java規定,運行時異常將由Java運行時系統自動拋出,允許應用程序忽略運行時異常。

? 對于方法運行中可能出現的Error,當運行方法不欲捕捉時,Java允許該方法不做任何拋出聲明。因為,大多數Error異常屬于永遠不能被允許發生的狀況,也屬于合理的應用程序不該捕捉的異常。

? 對于所有的可查異常,Java規定:一個方法必須捕捉,或者聲明拋出方法之外。也就是說,當一個方法選擇不捕捉可查異常時,它必須聲明將拋出異常。

? 能夠捕捉異常的方法,需要提供相符類型的異常處理器。所捕捉的異常,可能是由于自身語句所引發并拋出的異常,也可能是由某個調用的方法或者Java運行時 系統等拋出的異常。也就是說,一個方法所能捕捉的異常,一定是Java代碼在某處所拋出的異常。簡單地說,異常總是先被拋出,后被捕捉的。

? 任何Java代碼都可以拋出異常,如:自己編寫的代碼、來自Java開發環境包中代碼,或者Java運行時系統。無論是誰,都可以通過Java的throw語句拋出異常。

? 從方法中拋出的任何異常都必須使用throws子句。

? 捕捉異常通過try-catch語句或者try-catch-finally語句實現。

? 總體來說,Java規定:對于可查異常必須捕捉、或者聲明拋出。允許忽略不可查的RuntimeException和Error。

try {  // 可能會發生異常的程序代碼  
} catch (Type1 id1){  // 捕獲并處置try拋出的異常類型Type1  
}  
catch (Type2 id2){  //捕獲并處置try拋出的異常類型Type2  
}

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/535751.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/535751.shtml
英文地址,請注明出處:http://en.pswp.cn/news/535751.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

JDK源碼解析之 java.lang.Error

java.lang.Error 錯誤。是所有錯誤的基類&#xff0c;用于標識嚴重的程序運行問題。這些問題通常描述一些不應被應用程序捕獲的反常情況。 一、源碼部分 //繼承了java.lang.Throwable public class Error extends Throwable {//適用于java序列化機制,過判斷類的serialVersionU…

linux命令之有關網絡的操作命令

1&#xff0e;hostname 命令&#xff08;1&#xff09;一般格式&#xff1a;hostname [選項] [主機名]&#xff08;2&#xff09;說明&#xff1a;顯示或設置系統的主機名&#xff1b;如果無任何選項和主機名&#xff0c;則用于顯示系統的主機名。&#xff08;3&#xff09…

JDK源碼解析之 java.lang.Exception

異常。是所有異常的基類&#xff0c;用于標識一般的程序運行問題。這些問題通常描述一些會被應用程序捕獲的反常情況。 一、源碼部分 //繼承了java.lang.Throwable public class Exception extends Throwable {//適用于java序列化機制,過判斷類的serialVersionUID來驗證的版本…

linux命令之有關關機和查看系統信息的命令

shutdown 正常關機 reboot 重啟計算機 ps 查看目前程序執行的情況top 查看目前程序執行的情景和內存使用情況kill 終止一個進程date 更改或查看目前時間 一&#xff0e;查看系統的進程 要管理進程&#xff0c;首先要知…

HDFS-文件讀寫過程

一、文件讀取 Client向NameNode發起RPC請求&#xff0c;來確定請求文件block所在的位置&#xff1b;NameNode會視情況返回文件的部分或者全部block列表&#xff0c;對于每個block&#xff0c;NameNode 都會返回含有該 block 副本的 DataNode 地址&#xff1b; 這些返回的 DN 地…

linux命令復習之有關磁盤空間的命令

1&#xff0e;mount 命令&#xff08;1&#xff09;一般格式&#xff1a;mount 文件系統類型 [選項] 掛接設備&#xff08;2&#xff09;說明&#xff1a;將某個文件系統掛載到某個目錄上。當這個命令執行成功后&#xff0c;直到使用 umount 將這個文件系統移除為止。&…

HDFS-常用API操作

一、Maven <dependency><groupId>junit</groupId><artifactId>junit</artifactId><version>RELEASE</version> </dependency> <dependency><groupId>org.apache.logging.log4j</groupId><artifactId>…

linux命令之-管理文件和目錄的命令

一. 創建和刪除目錄的命令 1&#xff0e;mkdir 命令 &#xff08;1&#xff09;一般格式&#xff1a;mkdir [選項] 目錄名 &#xff08;2&#xff09;說明&#xff1a;該命令創建由目錄名命名的目錄。 &#xff08;3&#xff09;舉例1&#xff1a; 在目錄 /usr/fedora 下建…

Hive-簡介入門

Hive簡介 Hive最初是Facebook為了滿足對海量社交網絡數據的管理和機器學習的需求而產生和發展的。互聯網現在進入了大數據時代&#xff0c;大數據是現在互聯網的趨勢&#xff0c;而hadoop就是大數據時代里的核心技術&#xff0c;但是hadoop的mapreduce操作專業性太強&#xff0…

Hive-原理解析

一、Hive 架構 下面是Hive的架構圖。 Hive的體系結構可以分為以下幾部分 1、用戶接口&#xff1a;CLI&#xff08;hive shell&#xff09;&#xff1b;JDBC&#xff08;java訪問Hive&#xff09;&#xff1b;WEBUI&#xff08;瀏覽器訪問Hive&#xff09; 2、元數據&#x…

linux命令之history命令

在Linux系統上輸入命令并按下Enter后&#xff0c;這個命令就會存放在命令記錄表 ( ~/.bash_history )中&#xff0c;預定的記錄為1000條&#xff0c;這些都定義在環境變量中。列出所有的歷史記錄&#xff1a;#history 只列出最近10條記錄&#xff1a;#history 10 (注,history和…

Hive-配置安裝

一、HDFS安裝 1、解壓到指定位置tar -zxvf apache-hive-3.1.2-bin.tar.gz -C /usr/local/apps/ 2、改名mv apache-hive-3.1.2-bin/ hive-3.1.2 3、在conf目錄下添加Hadoop安裝路徑mv hive-env.sh.template hive-env.sh # 配置HADOOP_HOME路徑 export HADOOP_HOME/opt/module/…

linux文件系統概念目錄結構

文件系統概念一. 文件與目錄的定義1. 文件系統&#xff1a;它是磁盤上有特定格式的一片區域&#xff0c;操作系統通過文件系統可以方便地查尋和訪問其中所包含的磁盤塊&#xff1b;2. 文件&#xff1a;文件系統中存儲數據的一個命名的對象。3. 目錄&#xff1a;其中包含許多文件…

JDK源碼解析之 java.lang.Class

Java程序在運行時&#xff0c;Java運行時系統一直對所有的對象進行所謂的運行時類型標識。 這項信息紀錄了每個對象所屬的類。虛擬機通常使用運行時類型信息選準正確方法去執行&#xff0c;用來保存這些類型信息的類是Class類。Class類封裝一個對象和接口運行時的狀態&#xff…

Linux Vi常用技巧

VI常用技巧VI命令可以說是Unix/Linux世界里最常用的編輯文件的命令了&#xff0c;但是因為它的命令集眾多&#xff0c;很多人都不習慣使用它&#xff0c;其實您只需要掌握基本命令&#xff0c;然后加以靈活運用&#xff0c;就會發現它的優勢&#xff0c;并會逐漸喜歡使用這種方…

JDK源碼解析之 java.lang.ClassLoader

Class代表它的作用對象是類&#xff0c;Loader代表它的功能是加載&#xff0c;那么ClassLoader就是把一個以.class結尾的文件以JVM能識別的存儲形式加載到內存中。 一、核心方法 1、loadClass方法 protected Class<?> loadClass(String name, boolean resolve) throws…

Linux Vi的使用

一、插入文本┌──┬────────────┐│命令│描述 │├──┼────────────┤│i │在當前字符前插入文本 │├──┼────────────┤│I │在行首插入文本 │├──┼────────────┤│a │在當前字符后添加文本 │├──┼──…

Hive-beeline服務

Hive客戶端工具后續使用了Beeline 替代HiveCLI &#xff0c;并且后續版本也會廢棄掉HiveCLI 客戶端工具,Beeline是 Hive 0.11版本引入的新命令行客戶端工具,它是基于SQLLine CLI的JDBC客戶端。 Beeline支持嵌入模式(embedded mode)和遠程模式(remote mode)。在嵌入式模式下&am…

用戶賬號管理基本概念

什么是用戶賬號管理用戶賬號一般包括普通用戶賬號、管理賬號和系統賬號。為了鑒別用戶身份以及加強系統安全&#xff0c;系統為每個使用它的人分配了一個賬號&#xff0c;這就是普通用戶賬號。每個人擁有一個獨立的普通用戶賬號&#xff0c;每個賬號有不同的用戶名和密碼。用戶…

JDK源碼解析之 Java.lang.Compiler

Compiler類提供支持Java到本機代碼編譯器和相關服務。在設計上&#xff0c;它作為一個占位符在JIT編譯器實現。 一、源碼部分 public final class Compiler {private Compiler() {} // dont make instancesprivate static native void initialize();private st…