java怎么碰到异常跳过继续执行_Java异常处理很难吗?BAT大厂的架构师是怎么处理Java异常的?...
歡迎關注專欄《Java架構筑基》——專注于Java技術的研究與分享!
Java架構筑基?zhuanlan.zhihu.com- Java架構筑基——專注于Java技術的研究與分享!
- 后續文章將首發此專欄!
- 歡迎各位Java工程師朋友投稿和關注
- # 鏈接 Java程序員福利"常用資料分享"
異常是運行時在代碼序列中引起的非正常狀態。在不支持異常處理的計算機語言中,必須手動檢查和處理錯誤,Java語言則采用面向對象的方式管理運行時錯誤
一、基礎知識
Java異常是用來描述在一段代碼中發生的異常情況的對象。當出現引起異常的情況時,就會創建用來表示異常的對象,并在引起異常的方法中拋出異常對象。方法可以選擇自己處理異常或者傳遞異常交由其他方法來處理
Java異常處理通過五個關鍵字進行管理:try、catch、throw、throws、finally
在try代碼快中封裝可能發生異常的程序語句,對這些語句進行監視。如果在try代碼塊中發生異常,就會將異常拋出。代碼使用catch來捕獲異常,并可以定義一些方法來處理異常。系統生成的異常由Java運行時系統自動拋出。為了手動拋出異常,需要使用throw關鍵字。從方法中拋出的任何異常都必須通過一條throws子句進行指定。在try代碼塊結束之后必須執行的所有代碼則需要放在finally代碼塊中
二、異常類型
所有異常類型都是內置類Throwable的子類,Throwable的兩個子類將異常分為兩個不同的分支。一個分支是Exception類,這個類既可以用于用戶程序當前捕獲的異常情況,也可以用于創建自定義異常類型的子類。另一個分支是Error類,該類定義了在常規環境下不希望由程序捕獲的異常。Error類型的異常由Java運行時系統使用,以指示運行時系統本身發生了某些錯誤
三、未捕獲的異常
沒有被程序捕獲的所有異常,最終都會交由Java運行時系統提供的默認處理程序捕獲。默認處理程序會顯示一個描述異常的字符串,輸出異常發生的堆棧蹤跡并終止程序
例如,運行如下代碼:
public class Demo {public static void main(String[] args) {int a=2/0;}}生成的異常信息:
Exception in thread "main" java.lang.ArithmeticException: / by zeroat Demo.main(Demo.java:5)拋出的異常的類型是Exception的子類ArithmeticException,即算術異常,更具體地描述了發生的錯誤類型。Java提供了一些能與可能產生的各種運行時錯誤相匹配的內置異常類型
四、使用try和catch
進行主動的異常處理有兩個優點:第一,語序允許修復錯誤;第二,阻止程序自動終止
為了主動處理運行時錯誤,可以在try代碼塊中封裝希望監視的代碼,之后通過catch子句指定希望捕獲的異常類型。 例如,參照如下代碼:
public static void main(String[] args) {try{int a=10/0;System.out.println("輸出語句1");}catch(ArithmeticException e){System.out.println("輸出語句2");}System.out.println("輸出語句3");}輸出結果是:
輸出語句2輸出語句3代碼在進行除零操作時發生了異常,此時“輸出語句1”將無法得到被調用的機會。一旦拋出異常,程序控制就會從try代碼塊中轉移出來,進入catch代碼塊中。執行了catch語句后,就會繼續運行整個try/catch代碼塊的下一行
五、多條catch子句
在有些情況下,一個代碼塊可能會引發多個異常。對于這種情況,需要指定兩條或多條catch子句,用于捕獲不同類型的異常。當拋出異常時,按順序檢查每條catch語句,執行類型和異常相匹配的第一條catch子句,忽略其他catch子句,并繼續執行try/catch代碼塊后面的代碼
需要注意的是,異常子類必須位于異常超類之前,因為使用了某個超類的catch語句會捕獲這個超類及其所有子類的異常。因此,如果子類位于超類之后的話,永遠也不會到達子類。不可到達的代碼會被編譯器提示錯誤
參照如下代碼,通過Math的靜態方法random來隨機產生0和1兩個隨機數,生成的不同數值就會引發不同的異常,分別由不同的catch子句進行處理
public static void main(String[] args) { int random=(int) Math.round(Math.random());try{int a=10/random;int[] array={10};array[random]=1;}catch (ArithmeticException e) {System.out.println("ArithmeticException");}catch (ArrayIndexOutOfBoundsException e) {System.out.println("ArrayIndexOutOfBoundsException");}System.out.println("代碼塊結束");}此外,也可以通過多重捕獲的方式來使用相同的catch子句捕獲兩個或更多個異常。在catch子句中使用或運算符(|)分隔每個異常,每個多重捕獲參數都被隱式地聲明為final類型
public static void main(String[] args) { int random=(int) Math.round(Math.random());try{int a=10/random;int[] array={10};array[random]=1;}catch(ArithmeticException | ArrayIndexOutOfBoundsException e){System.out.println("兩個異常之一");}}六、throw
在之前的例子中,捕獲的異常都是由Java運行時系統拋出的異常,可以通過throw語句顯式地拋出異常
throw的一般形式如下所示:
throw ThrowableInstanceThrowableInstance必須是Throwable或其子類類型的對象。throw語句之后的執行流程會立即停止,所有的后續語句都不會執行,然后按順序依次檢查所有的catch語句,檢查是否和異常類型相匹配。如果沒有找到匹配的catch語句,那么默認的異常處理程序會終止程序并輸出堆棧蹤跡
例如,運行以下代碼,將得到輸出結果:“NullPointerException”
public class Demo {public static void demo(){throw new NullPointerException("NullPointer");}public static void main(String[] args) {try{demo();}catch (NullPointerException e) {System.out.println("NullPointerException");}}}但如果catch子句的異常與throw拋出的異常類型不匹配時,異常將由Java默認的異常處理程序來處理
例如,運行以下代碼:
public class Demo {public static void demo(){throw new NullPointerException("NullPointer");}public static void main(String[] args) {try{demo();}catch (ArrayIndexOutOfBoundsException e) {System.out.println("ArrayIndexOutOfBoundsException");}}}運行結果是:
Exception in thread "main" java.lang.NullPointerException: NullPointerat Demo.demo(Demo.java:4)at Demo.main(Demo.java:9)七、throws
如果方法可能引發自身不進行處理的異常,就必須通過throws關鍵字來向方法的調用者指明要拋出的異常類型。 方法可能拋出的所有異常都必須在throws子句中進行聲明,否則將產生編譯時錯誤
例如,參照以下代碼,該程序試圖拋出無法匹配的異常,因為程序沒有指定throws子句來聲明這一事實,所以程序無法編譯
public class Demo {public static void demo(){throw new IllegalAccessException("IllegalAccess");}public static void main(String[] args) {demo();}}為了使代碼能夠運行,需要將之進行如下修改
public class Demo {public static void demo() throws IllegalAccessException{throw new IllegalAccessException("IllegalAccess");}public static void main(String[] args) {try {demo();} catch (IllegalAccessException e) {System.out.println(e.getMessage());}}}八、finally
當拋出異常后,方法的執行流程將不會按照原先的順序進行,這對于某些方法來說是個問題。例如,如果在方法中打開了一個文件,我們并不希望因為拋出了異常導致關閉文件的代碼被跳過而不執行。finally關鍵字就是來解決這種情況的。 使用finally可以創建一個代碼塊,該代碼塊會在執行try/catch代碼塊之后執行,且在執行try/catch代碼塊后面的代碼之前執行。不管是否有異常拋出,都將執行finally代碼塊
只要方法從try/catch代碼塊內部返回到調用者,不管是通過未捕獲的異常還是使用顯式的返回語句,都會在方法返回之前執行finally子句
例如,如下的輸出結果將是:2
public class Demo {public static int demo(){try{int a=10/0;System.out.println(a);}catch(Exception e){return 1;}finally {return 2;}}public static void main(String[] args) {System.out.println(demo());}}九、鏈式異常
鏈式異常用于為異常關聯另一個異常,第二個異常用于描述當前異常產生的原因。例如,某個方法從文件讀取數值來作為除法運算的除數,由于發生了I/O錯誤導致獲取到的數值是0,從而導致了ArithmeticException異常
如果想要讓代碼調用者知道背后的原因是I/O錯誤,使用鏈式異常就可以來處理這種情況以及其他存在多層異常的情況
為了使用鏈式異常,Throwable有兩個構造函數和兩個方法用于處理這種情況
兩個構造函數:
Throwable(Throwable cause)Throwable(String message, Throwable cause)cause即是用于指定引發當前異常的背后原因,message則可以用于同時指定異常描述
兩個方法:
Throwable getCause()Throwable initCause(Throwable cause)getCause() 方法用來返回引發當前異常的異常,如果不存在背后異常則返回null
initCause(Throwable cause) 方法將cause和明面上的異常關聯到一起,并返回對異常的引用。因此可以在創建異常之后將異常和背后異常關聯到一起。但是,背后異常只能設置一次,即initCause(Throwable cause) 方法只能調用一次。此外,如果通過構造函數設置了背后異常,也不能再使用該方法來設置背后異常了
例如,參照如下代碼:
public class Demo {public static void demo(){NullPointerException nullPointerException=new NullPointerException("nullPointer");nullPointerException.initCause(new ArithmeticException("Arithmetic"));throw nullPointerException;}public static void main(String[] args) {try {demo();} catch (Exception e) {System.out.println(e.getMessage());System.out.println(e.getCause().getMessage());}}}運行結果是:
nullPointer Arithmetic鏈式異常可以包含所需要的任意深度,但是,過長的異常鏈可能是一種不良的設計
# 鏈接 Java程序員福利"常用資料分享"
總結
以上是生活随笔為你收集整理的java怎么碰到异常跳过继续执行_Java异常处理很难吗?BAT大厂的架构师是怎么处理Java异常的?...的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: c语言把数据存放在文件中,急求如何将下列
- 下一篇: kibana java script_E