讓咱們準備一個函數:架構
而後,反編譯他的字節碼:jvm
首先咱們介紹異常表:在編譯生成的字節碼中,每一個方法都附帶一個異常表。函數
異常表中的每個條目表明一個異常處理器,而且由 from 指針、to 指針、target 指針以及所捕獲的異常類型構成。這些指針的值是字節碼索引用以定位字節碼。學習
下圖就是我特別指出的JVM字節碼中的異常表部分。線程
咱們來分析一下這幾個語句的執行流程,首先執行:指針
這至關於執行:
cdn
再來:
blog
上圖至關於執行
索引
有人問:try去哪了?
get
我立刻就要介紹。此時idiv執行完就有異常了,有異常了先找異常表。
我再貼一下異常表,他是怎麼搜索的呢?
當程序觸發異常時,Java 虛擬機會從上至下遍歷異常表中的全部條目。
當觸發異常的字節碼的索引值在某個異常表條目的監控範圍內,Java 虛擬機會判斷所拋出的異常和該條目想要捕獲的異常是否匹配。
若是匹配,Java 虛擬機會將控制流轉移至該條目 target 指針指向的字節碼。
咱們看 ,是第四個索引指向的字節碼出了問題,顯然,此時應該匹配紅線這一條記錄,從而跳轉到第14個索引的字節碼。
咱們看他怎麼作的?
new出一個RuntimeException並拋出,它就是
這一句,按照咱們剛纔的流程,此時依然須要找到這個RuntimeException在哪一個異常表的條目中
此時匹配到異常表的條目,跳轉到字節碼索引23
繼續拋出RuntimeExcpetion,能夠注意到 這實際上對應了
這個語句,因而咱們能夠知道,在三個都出現異常的狀況下,實際上最終向外拋出的異常是finally裏面的異常。
能夠看到當31索引處調用athrow語句拋出異常時,此時異常表沒有任何一個條目可以匹配該異常,此時怎麼辦呢?
若是遍歷完全部異常表條目,Java 虛擬機仍未匹配到異常處理器,那麼它會彈出當前方法對應的 Java 棧幀,而且在調用者中重複上述操做。
在最壞狀況下,Java 虛擬機須要遍歷當前線程 Java 棧上全部方法的異常表。
事實上分析以上的總體的所有語句你能夠發現,jvm層面有真正的finally嗎?
沒有
如今的作法是,複製 finally 代碼塊的內容,分別放在 try-catch 代碼塊全部正常執行路徑以及異常執行路徑的出口中。不管是否出現異常,確保必定會執行finally語句。
剛纔catch出了異常,依然執行finally語句就能夠發現這一點。至於其餘路徑,你們能夠自行驗證。我就在這裏拋磚引玉了。
至於爲何2-6發生任何異常都跳轉到23?你們能夠本身想一下這個問題。
我就提示一點 2-6 target爲14的條目表明的catch是不能捕獲全部異常的,可是你要確保finally的語句可以執行。而2-6恰巧是try語句塊的內容。23這個索引恰巧是finally語句的一份複製。
END
我的公衆號:石杉的架構筆記(ID:shishan100)
歡迎長按下圖關注公衆號:石杉的架構筆記!
公衆號後臺回覆資料,獲取做者獨家祕製學習資料
石杉的架構筆記,BAT架構經驗傾囊相授