亚洲乱码中文字幕综合,中国熟女仑乱hd,亚洲精品乱拍国产一区二区三区,一本大道卡一卡二卡三乱码全集资源,又粗又黄又硬又爽的免费视频

JVM如何處理異常深入詳解

 更新時間:2019年01月07日 08:39:41   作者:技術小黑屋  
異常處理的兩大元素:拋出異常、捕獲異常,非正常處理的兩個方法。下面這篇文章主要給大家介紹了關于JVM如何處理異常的相關資料,文中通過示例代碼介紹的非常詳細,需要的朋友可以參考下

前言

無論你是使用何種編程語言,在日常的開發(fā)過程中,都會不可避免的要處理異常。今天本文將嘗試講解一些JVM如何處理異常問題,希望能夠講清楚這個內部的機制,如果對大家有所啟發(fā)和幫助,則甚好。

當異常不僅僅是異常

我們在標題中提到了異常,然而這里指的異常并不是單純的Exception,而是更為寬泛的Throwable。只是我們工作中習以為常的將它們(錯誤地)這樣稱謂。

關于Exception和Throwable的關系簡單描述一下

  • Exception屬于Throwable的子類,Throwable的另一個重要的子類是Error
  • throw可以拋出的都是Throwable和其子類,catch可捕獲的也是Throwable和其子類。

除此之外,但是Exception也有一些需要我們再次強調的

  • Exception分為兩種類型,一種為Checked Exception,另一種為unchecked Exception
  • Checked Exception,比如最常見的IOException,這種異常需要調用處顯式處理,要么使用try catch捕獲,要么再次拋出去。
  • Unchecked Exception指的是所有繼承自Error(包含自身)或者是RuntimeException(包含自身)的類。這些異常不強制在調用處進行處理。但是也可以try catch處理。

注:本文暫不做Checked Exception設計的好壞的分析。

Exception Table 異常表

提到JVM處理異常的機制,就需要提及Exception Table,以下稱為異常表。我們暫且不急于介紹異常表,先看一個簡單的Java處理異常的小例子。

public static void simpleTryCatch() {
 try {
 testNPE();
 } catch (Exception e) {
 e.printStackTrace();
 }
}

上面的代碼是一個很簡單的例子,用來捕獲處理一個潛在的空指針異常。

當然如果只是看簡簡單單的代碼,我們很難看出什么高深之處,更沒有了今天文章要談論的內容。

所以這里我們需要借助一把神兵利器,它就是javap,一個用來拆解class文件的工具,和javac一樣由JDK提供。

然后我們使用javap來分析這段代碼(需要先使用javac編譯)

//javap -c Main
 public static void simpleTryCatch();
 Code:
 0: invokestatic #3   // Method testNPE:()V
 3: goto  11
 6: astore_0
 7: aload_0
 8: invokevirtual #5   // Method java/lang/Exception.printStackTrace:()V
 11: return
 Exception table:
 from to target type
  0 3 6 Class java/lang/Exception

看到上面的代碼,應該會有會心一笑,因為終于看到了Exception table,也就是我們要研究的異常表。

異常表中包含了一個或多個異常處理者(Exception Handler)的信息,這些信息包含如下

  • from 可能發(fā)生異常的起始點
  • to 可能發(fā)生異常的結束點
  • target 上述from和to之前發(fā)生異常后的異常處理者的位置
  • type 異常處理者處理的異常的類信息

那么異常表用在什么時候呢

答案是異常發(fā)生的時候,當一個異常發(fā)生時

1.JVM會在當前出現(xiàn)異常的方法中,查找異常表,是否有合適的處理者來處理

2.如果當前方法異常表不為空,并且異常符合處理者的from和to節(jié)點,并且type也匹配,則JVM調用位于target的調用者來處理。

3.如果上一條未找到合理的處理者,則繼續(xù)查找異常表中的剩余條目

4.如果當前方法的異常表無法處理,則向上查找(彈棧處理)剛剛調用該方法的調用處,并重復上面的操作。

5.如果所有的棧幀被彈出,仍然沒有處理,則拋給當前的Thread,Thread則會終止。

6.如果當前Thread為最后一個非守護線程,且未處理異常,則會導致JVM終止運行。

以上就是JVM處理異常的一些機制。

try catch -finally

除了簡單的try-catch外,我們還常常和finally做結合使用。比如這樣的代碼

public static void simpleTryCatchFinally() {
 try {
 testNPE();
 } catch (Exception e) {
 e.printStackTrace();
 } finally {
 System.out.println("Finally");
 }
}

同樣我們使用javap分析一下代碼

public static void simpleTryCatchFinally();
 Code:
 0: invokestatic #3   // Method testNPE:()V
 3: getstatic #6   // Field java/lang/System.out:Ljava/io/PrintStream;
 6: ldc  #7   // String Finally
 8: invokevirtual #8   // Method java/io/PrintStream.println:(Ljava/lang/String;)V
 11: goto  41
 14: astore_0
 15: aload_0
 16: invokevirtual #5   // Method java/lang/Exception.printStackTrace:()V
 19: getstatic #6   // Field java/lang/System.out:Ljava/io/PrintStream;
 22: ldc  #7   // String Finally
 24: invokevirtual #8   // Method java/io/PrintStream.println:(Ljava/lang/String;)V
 27: goto  41
 30: astore_1
 31: getstatic #6   // Field java/lang/System.out:Ljava/io/PrintStream;
 34: ldc  #7   // String Finally
 36: invokevirtual #8   // Method java/io/PrintStream.println:(Ljava/lang/String;)V
 39: aload_1
 40: athrow
 41: return
 Exception table:
 from to target type
  0 3 14 Class java/lang/Exception
  0 3 30 any
  14 19 30 any

和之前有所不同,這次

  • 異常表中,有三條數(shù)據(jù),而我們僅僅捕獲了一個Exception
  • 異常表的后兩個item的type為any

上面的三條異常表item的意思為

  • 如果0到3之間,發(fā)生了Exception類型的異常,調用14位置的異常處理者。
  • 如果0到3之間,無論發(fā)生什么異常,都調用30位置的處理者
  • 如果14到19之間(即catch部分),不論發(fā)生什么異常,都調用30位置的處理者。

再次分析上面的Java代碼,finally里面的部分已經(jīng)被提取到了try部分和catch部分。我們再次調一下代碼來看一下

public static void simpleTryCatchFinally();
 Code:
 //try 部分提取finally代碼,如果沒有異常發(fā)生,則執(zhí)行輸出finally操作,直至goto到41位置,執(zhí)行返回操作。 

 0: invokestatic #3   // Method testNPE:()V
 3: getstatic #6   // Field java/lang/System.out:Ljava/io/PrintStream;
 6: ldc  #7   // String Finally
 8: invokevirtual #8   // Method java/io/PrintStream.println:(Ljava/lang/String;)V
 11: goto  41

 //catch部分提取finally代碼,如果沒有異常發(fā)生,則執(zhí)行輸出finally操作,直至執(zhí)行got到41位置,執(zhí)行返回操作。
 14: astore_0
 15: aload_0
 16: invokevirtual #5   // Method java/lang/Exception.printStackTrace:()V
 19: getstatic #6   // Field java/lang/System.out:Ljava/io/PrintStream;
 22: ldc  #7   // String Finally
 24: invokevirtual #8   // Method java/io/PrintStream.println:(Ljava/lang/String;)V
 27: goto  41
 //finally部分的代碼如果被調用,有可能是try部分,也有可能是catch部分發(fā)生異常。
 30: astore_1
 31: getstatic #6   // Field java/lang/System.out:Ljava/io/PrintStream;
 34: ldc  #7   // String Finally
 36: invokevirtual #8   // Method java/io/PrintStream.println:(Ljava/lang/String;)V
 39: aload_1
 40: athrow //如果異常沒有被catch捕獲,而是到了這里,執(zhí)行完finally的語句后,仍然要把這個異常拋出去,傳遞給調用處。
 41: return

Catch先后順序的問題

我們在代碼中的catch的順序決定了異常處理者在異常表的位置,所以,越是具體的異常要先處理,否則就會出現(xiàn)下面的問題

private static void misuseCatchException() {
 try {
 testNPE();
 } catch (Throwable t) {
 t.printStackTrace();
 } catch (Exception e) { //error occurs during compilings with tips Exception Java.lang.Exception has already benn caught.
 e.printStackTrace();
 }
}

這段代碼會導致編譯失敗,因為先捕獲Throwable后捕獲Exception,會導致后面的catch永遠無法被執(zhí)行。

Return 和finally的問題

這算是我們擴展的一個相對比較極端的問題,就是類似這樣的代碼,既有return,又有finally,那么finally導致會不會執(zhí)行

public static String tryCatchReturn() {
 try {
 testNPE();
 return "OK";
 } catch (Exception e) {
 return "ERROR";
 } finally {
 System.out.println("tryCatchReturn");
 }
}

答案是finally會執(zhí)行,那么還是使用上面的方法,我們來看一下為什么finally會執(zhí)行。

public static java.lang.String tryCatchReturn();
 Code:
 0: invokestatic #3   // Method testNPE:()V
 3: ldc  #6   // String OK
 5: astore_0
 6: getstatic #7   // Field java/lang/System.out:Ljava/io/PrintStream;
 9: ldc  #8   // String tryCatchReturn
 11: invokevirtual #9   // Method java/io/PrintStream.println:(Ljava/lang/String;)V
 14: aload_0
 15: areturn 返回OK字符串,areturn意思為return a reference from a method
 16: astore_0
 17: ldc  #10   // String ERROR
 19: astore_1
 20: getstatic #7   // Field java/lang/System.out:Ljava/io/PrintStream;
 23: ldc  #8   // String tryCatchReturn
 25: invokevirtual #9   // Method java/io/PrintStream.println:(Ljava/lang/String;)V
 28: aload_1
 29: areturn //返回ERROR字符串
 30: astore_2
 31: getstatic #7   // Field java/lang/System.out:Ljava/io/PrintStream;
 34: ldc  #8   // String tryCatchReturn
 36: invokevirtual #9   // Method java/io/PrintStream.println:(Ljava/lang/String;)V
 39: aload_2
 40: athrow 如果catch有未處理的異常,拋出去。

行文倉促,加之本人水平有限,有錯誤的地方,請指出。

參考文章:

  • http://blog.jamesdbloom.com/JVMInternals.html#exception_table
  • https://blog.takipi.com/the-surprising-truth-of-java-exceptions-what-is-really-going-on-under-the-hood/
  • https://en.wikipedia.org/wiki/Java_bytecode_instruction_listings
  • https://dzone.com/articles/the-truth-of-java-exceptions-whats-really-going-on

總結

以上就是這篇文章的全部內容了,希望本文的內容對大家的學習或者工作具有一定的參考學習價值,如果有疑問大家可以留言交流,謝謝大家對腳本之家的支持。

相關文章

  • IDEA添加Java類注釋模版的方法

    IDEA添加Java類注釋模版的方法

    本篇文章主要介紹了IDEA添加Java類注釋模版的方法,小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧
    2017-12-12
  • Java中的Runnable,Callable,F(xiàn)uture,F(xiàn)utureTask的比較

    Java中的Runnable,Callable,F(xiàn)uture,F(xiàn)utureTask的比較

    這篇文章主要介紹了Java中的Runnable,Callable,F(xiàn)uture,F(xiàn)utureTask的比較的相關資料,需要的朋友可以參考下
    2017-02-02
  • Java開發(fā)之Lombok指南

    Java開發(fā)之Lombok指南

    Lombok是一款Java開發(fā)插件,使得Java開發(fā)者可以通過其定義的一些注解來消除業(yè)務工程中冗長和繁瑣的代碼,它能夠在編譯源代碼期間自動幫我們生成這些方法,并沒有如反射那樣降低程序的性能。下面我們來詳細了解一下吧
    2019-06-06
  • Lombok和MapStruct整合詳情

    Lombok和MapStruct整合詳情

    這篇文章主要介紹了Lombok和MapStruct整合詳情,文章基于Java的相關資料展開詳細內容,需要的小伙伴可以參考一下
    2022-05-05
  • Spring Batch 如何自定義ItemReader

    Spring Batch 如何自定義ItemReader

    這篇文章主要介紹了Spring Batch 如何自定義ItemReader的實現(xiàn)方式,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2021-09-09
  • Java?Ribbon與openfeign區(qū)別和用法講解

    Java?Ribbon與openfeign區(qū)別和用法講解

    Ribbon是基于Netflix?Ribbon實現(xiàn)的一套客戶端負載均衡的工具,主要功能是提供客戶端的軟件負載均衡算法和服務調用。openfeign對Feign進行了增強,使其支持Spring MVC注解,另外還整合了Ribbon和Nacos,從而使得Feign的使用更加方便
    2022-08-08
  • SpringBoot使用JUL實現(xiàn)日志記錄功能

    SpringBoot使用JUL實現(xiàn)日志記錄功能

    在SpringBoot中,我們可以使用多種日志框架進行日志記錄,其中,JUL(Java Util Logging)是Java平臺自帶的日志框架,它提供了簡單的 API 和配置,可以輕松地進行日志記錄,本文將介紹如何在 SpringBoot中使用JUL進行日志記錄,并提供示例代碼
    2023-06-06
  • SpringBoot整合PowerJob實現(xiàn)定時任務調度

    SpringBoot整合PowerJob實現(xiàn)定時任務調度

    最近項目需要使用定時任務,而使用了PowerJob做任務調度模塊,感覺這個框架真香,今天我們就來深入了解一下新一代的定時任務框架——PowerJob,需要的朋友可以參考下
    2024-03-03
  • 詳解java并發(fā)編程(2) --Synchronized與Volatile區(qū)別

    詳解java并發(fā)編程(2) --Synchronized與Volatile區(qū)別

    這篇文章主要介紹了Synchronized與Volatile區(qū)別,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧
    2019-04-04
  • Springboot配置suffix指定mvc視圖的后綴方法

    Springboot配置suffix指定mvc視圖的后綴方法

    這篇文章主要介紹了Springboot配置suffix指定mvc視圖的后綴方法,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2021-07-07

最新評論