国产xxxx99真实实拍_久久不雅视频_高清韩国a级特黄毛片_嗯老师别我我受不了了小说

資訊專欄INFORMATION COLUMN

聊聊Java的異常機(jī)制及實(shí)現(xiàn)

Towers / 2673人閱讀

摘要:是那些可能在虛擬機(jī)正常運(yùn)行期間拋出的異常的超類。運(yùn)行時(shí)異常定義及其子類都被稱為運(yùn)行時(shí)異常。對(duì)于語言中的關(guān)鍵字和,虛擬機(jī)中并沒有特殊的字節(jié)碼指令去支持它們,都是通過編譯器生成字節(jié)碼片段以及不同的異常處理器來實(shí)現(xiàn)。

前言

在一些傳統(tǒng)的編程語言,如C語言中,并沒有專門處理異常的機(jī)制,程序員通常用方法的特定返回值來表示異常情況,并且程序的正常流程和異常流程都采用同樣的流程控制語句。
Java語言按照面向?qū)ο蟮乃枷雭硖幚懋惓#沟贸绦蚓哂懈玫目删S護(hù)性。Java異常處理機(jī)制具有以下優(yōu)點(diǎn):

把各種不同類型的異常情況進(jìn)行分類,用Java類來表示異常情況,這種類被稱為異常類。把異常情況表示成異常類,可以充分發(fā)揮類的可擴(kuò)展和可重用的優(yōu)勢(shì)。

異常流程的代碼和正常流程的代碼分離,提高了程序的可讀性,簡化程序的結(jié)構(gòu)。

可以靈活的處理異常,如果當(dāng)前方法有能力處理異常,就捕獲并處理它,否則只需要拋出異常,由方法調(diào)用。

Java異常基礎(chǔ)

關(guān)于異常的使用我就不再多說了,在這里還是先提幾個(gè)問題:

catch多個(gè)異常的時(shí)候,按什么規(guī)則選擇呢

throws異常是否是函數(shù)簽名的一部分呢

覆蓋父類的帶throws的函數(shù)是否也需要加throws呢

同時(shí)實(shí)現(xiàn)多個(gè)接口中同名拋出異常的函數(shù)最后拋出異常的集合是什么呢

接下來我們回答其中的部分問題,先看一個(gè)例子

可以看到Java是按照catch聲明的順序來捕獲異常的,且編譯器不允許將父類異常聲明在子類之前。

throws異常顯然不是函數(shù)的一部分,因?yàn)閮蓚€(gè)throws不同的同名同參數(shù)的函數(shù)不允許重載。

從上圖我們可以看出覆蓋對(duì)拋出異常的聲明并沒有要求。

上圖可以看出編譯器對(duì)接口的方法實(shí)現(xiàn)也并無什么要求,重點(diǎn)在于try-catch塊的檢查,你不能catch一個(gè)你在throw塊里不可能拋出的檢查類型異常,而這種判斷是通過你調(diào)用方法聲明的拋出異常,即使你在方法實(shí)現(xiàn)里不可能拋出該異常,你加在throws里,一樣可以蒙騙編譯器。對(duì)于方法聲明的拋出異常,只有一個(gè)條件需要滿足,那就是你的實(shí)現(xiàn)中可能拋出的檢查類型異常要么處理要么聲明拋出,不需要考慮繼承和實(shí)現(xiàn)關(guān)系給throws帶來的影響,這是參考文章中的一點(diǎn)小錯(cuò)誤,特此更正。

Java異常類的架構(gòu)

Throwable

Throwable是 Java 語言中所有錯(cuò)誤或異常的超類。

Throwable包含兩個(gè)子類: Error 和 Exception。它們通常用于指示發(fā)生了異常情況。

Throwable包含了其線程創(chuàng)建時(shí)線程執(zhí)行堆棧的快照,它提供了printStackTrace()等接口用于獲取堆棧跟蹤數(shù)據(jù)等信息。

Exception

Exception及其子類是 Throwable 的一種形式,它指出了合理的應(yīng)用程序想要捕獲的條件。

RuntimeException

RuntimeException是那些可能在 Java 虛擬機(jī)正常運(yùn)行期間拋出的異常的超類。

編譯器不會(huì)檢查RuntimeException異常。例如,除數(shù)為零時(shí),拋出ArithmeticException異常。RuntimeException是ArithmeticException的超類。當(dāng)代碼發(fā)生除數(shù)為零的情況時(shí),倘若既"沒有通過throws聲明拋出ArithmeticException異常",也"沒有通過try...catch...處理該異常",也能通過編譯。這就是我們所說的"編譯器不會(huì)檢查RuntimeException異常"!

如果代碼會(huì)產(chǎn)生RuntimeException異常,則需要通過修改代碼進(jìn)行避免。例如,若會(huì)發(fā)生除數(shù)為零的情況,則需要通過代碼避免該情況的發(fā)生!

Error

和Exception一樣,Error也是Throwable的子類。它用于指示合理的應(yīng)用程序不應(yīng)該試圖捕獲的嚴(yán)重問題,大多數(shù)這樣的錯(cuò)誤都是異常條件。

和RuntimeException一樣,編譯器也不會(huì)檢查Error。

Java將可拋出(Throwable)的結(jié)構(gòu)分為三種類型:被檢查的異常(Checked Exception),運(yùn)行時(shí)異常(RuntimeException)和錯(cuò)誤(Error)。

(01) 運(yùn)行時(shí)異常

定義: RuntimeException及其子類都被稱為運(yùn)行時(shí)異常。

特點(diǎn): Java編譯器不會(huì)檢查它。也就是說,當(dāng)程序中可能出現(xiàn)這類異常時(shí),倘若既"沒有通過throws聲明拋出它",也"沒有用try-catch語句捕獲它",還是會(huì)編譯通過。例如,除數(shù)為零時(shí)產(chǎn)生的ArithmeticException異常,數(shù)組越界時(shí)產(chǎn)生的IndexOutOfBoundsException異常,fail-fail機(jī)制產(chǎn)生的ConcurrentModificationException異常等,都屬于運(yùn)行時(shí)異常。

雖然Java編譯器不會(huì)檢查運(yùn)行時(shí)異常,但是我們也可以通過throws進(jìn)行聲明拋出,也可以通過try-catch對(duì)它進(jìn)行捕獲處理。

如果產(chǎn)生運(yùn)行時(shí)異常,則需要通過修改代碼來進(jìn)行避免。例如,若會(huì)發(fā)生除數(shù)為零的情況,則需要通過代碼避免該情況的發(fā)生!

(02) 被檢查的異常

定義: Exception類本身,以及Exception的子類中除了"運(yùn)行時(shí)異常"之外的其它子類都屬于被檢查異常。

特點(diǎn): Java編譯器會(huì)檢查它。此類異常,要么通過throws進(jìn)行聲明拋出,要么通過try-catch進(jìn)行捕獲處理,否則不能通過編譯。例如,CloneNotSupportedException就屬于被檢查異常。當(dāng)通過clone()接口去克隆一個(gè)對(duì)象,而該對(duì)象對(duì)應(yīng)的類沒有實(shí)現(xiàn)Cloneable接口,就會(huì)拋出CloneNotSupportedException異常。

被檢查異常通常都是可以恢復(fù)的。

(03) 錯(cuò)誤

定義: Error類及其子類。

特點(diǎn): 和運(yùn)行時(shí)異常一樣,編譯器也不會(huì)對(duì)錯(cuò)誤進(jìn)行檢查。

當(dāng)資源不足、約束失敗、或是其它程序無法繼續(xù)運(yùn)行的條件發(fā)生時(shí),就產(chǎn)生錯(cuò)誤。程序本身無法修復(fù)這些錯(cuò)誤的。例如,VirtualMachineError就屬于錯(cuò)誤。

按照J(rèn)ava慣例,我們是不應(yīng)該是實(shí)現(xiàn)任何新的Error子類的!

Java異常的實(shí)現(xiàn)原理 異常的捕獲原理

首先介紹下java的異常表(Exception table),異常表是JVM處理異常的關(guān)鍵點(diǎn),在java類中的每個(gè)方法中,會(huì)為所有的try-catch語句,生成一張異常表,存放在字節(jié)碼的最后,該表記錄了該方法內(nèi)每個(gè)異常發(fā)生的起止指令和處理指令。

接下來看一個(gè)例子:

public void catchException() {  
    long l = System.nanoTime();  
    for (int i = 0; i < testTimes; i++) { 
        try {  
            throw new Exception();  
        } catch (Exception e) { 
            //nothing to do
        }  
    }
    System.out.println("拋出并捕獲異常:" + (System.nanoTime() - l));  
}

字節(jié)碼如下

面請(qǐng)結(jié)合java代碼和生成的字節(jié)碼來看下面的指令分析:
0-4號(hào): 執(zhí)行try前面的語句
5號(hào): 執(zhí)行try語句前保存現(xiàn)場
6號(hào): 執(zhí)行try語句后跳轉(zhuǎn)指令行,圖中表示跳轉(zhuǎn)到22
9-17號(hào): try-catch代碼生成指令,結(jié)合紅色框圖異常表,表示9-17號(hào)指令若有Exception異常拋出就執(zhí)行17行指令.
16號(hào): athrow 表示拋出異常
17號(hào): astore 表示jvm將該異常實(shí)例存儲(chǔ)到局部變量表中方便一旦出方法棧調(diào)用方可以找到
22號(hào): 恢復(fù)try語句執(zhí)行前保存的現(xiàn)場
對(duì)比指令分析,再結(jié)合使用try-catch代碼分析:

若try沒有拋出異常,則繼續(xù)執(zhí)行完try語句,跳過catch語句,此時(shí)就是從指令6跳轉(zhuǎn)到指令22.

若try語句拋出異常則執(zhí)行指令17,將異常保存起來,若異常被方法拋出,調(diào)用方拿到異常可用于異常層次索引。

通過以上的分析,可以知道JVM是怎么捕獲并處理異常,其實(shí)就是使用goto指令來做上下文切換。

異常的處理機(jī)制

上面大致介紹了異常是如何產(chǎn)生并捕獲的,接下來我們?cè)敿?xì)講講athrow指令拋出異常后的故事,也就是如何處理異常的問題。

athrow指令,這個(gè)指令運(yùn)作過程大致是首先檢查操作棧頂,這時(shí)棧頂必須存在一個(gè)reference類型的值,并且是java.lang.Throwable的子類(虛擬機(jī)規(guī)范中要求如果遇到null則當(dāng)作NPE異常使用),然后暫時(shí)先把這個(gè)引用出棧,接著搜索本方法的異常表,找一下本方法中是否有能處理這個(gè)異常的handler,如果能找到合適的handler就會(huì)重新初始化PC寄存器指針指向此異常handler的第一個(gè)指令的偏移地址。接著把當(dāng)前棧幀的操作棧清空,再把剛剛出棧的引用重新入棧。如果在當(dāng)前方法中很悲劇的找不到handler,那只好把當(dāng)前方法的棧幀出棧(這個(gè)棧是VM棧,不要和前面的操作棧搞混了,棧幀出棧就意味著當(dāng)前方法退出),這個(gè)方法的調(diào)用者的棧幀就自然在這條線程VM棧的棧頂了,然后再對(duì)這個(gè)新的當(dāng)前方法再做一次剛才做過的異常handler搜索,如果還是找不到,繼續(xù)把這個(gè)棧幀踢掉,這樣一直到找,要么找到一個(gè)能使用的handler,轉(zhuǎn)到這個(gè)handler的第一條指令開始繼續(xù)執(zhí)行,要么把VM棧的棧幀拋光了都沒有找到期望的handler,這樣的話這條線程就只好被迫終止、退出了。

對(duì)于Java語言中的關(guān)鍵字catch和finally,虛擬機(jī)中并沒有特殊的字節(jié)碼指令去支持它們,都是通過編譯器生成字節(jié)碼片段以及不同的異常處理器來實(shí)現(xiàn)。

我們總結(jié)一下athrow指令中虛擬機(jī)可能做的事情:

檢查棧頂異常對(duì)象類型(只檢查是不是null,是否referance類型,是否Throwable的子類一般在類驗(yàn)證階段的數(shù)據(jù)流分析中做,或者索性不做靠編譯器保證了,編譯時(shí)寫到Code屬性的StackMapTable中,在加載時(shí)僅做類型驗(yàn)證)

把異常對(duì)象的引用出棧

搜索異常表,找到匹配的異常handler

重置PC寄存器狀態(tài)

清理操作棧

把異常對(duì)象的引用入棧

把異常方法的棧幀逐個(gè)出棧(這里的棧是VM棧)

殘忍地終止掉當(dāng)前線程。

異常到底慢不慢

這里直接給出一些結(jié)論吧:

新建一個(gè)異常對(duì)象比新建一個(gè)普通對(duì)象在耗時(shí)上多一個(gè)數(shù)量級(jí),拋出并捕獲異常的耗時(shí)比新建一個(gè)異常在耗時(shí)上也要多一個(gè)數(shù)量級(jí)。創(chuàng)建一個(gè)異常對(duì)象卻是要比一個(gè)普通對(duì)象耗時(shí)多,捕獲一個(gè)異常耗時(shí)更甚。捕獲的過程我們上面已經(jīng)簡要介紹了,為什么新建一個(gè)異常對(duì)象這么耗時(shí)?且看源碼:

在java中,所有的異常都繼承自Throwable類,Throwable的構(gòu)造函數(shù)

public Throwable() {
    ...
    fillInStackTrace();
    ...
}

有個(gè)nativ方法public synchronized native Throwable fillInStackTrace();這個(gè)方法會(huì)存入當(dāng)前線程的堆棧信息。也就是說每次創(chuàng)建一個(gè)異常實(shí)例都會(huì)把堆棧信息存一遍。這就是時(shí)間開銷的主要來源了。

這個(gè)時(shí)候我們可以下一個(gè)結(jié)論:新建異常對(duì)象比創(chuàng)建一個(gè)普通對(duì)象是要更加的耗時(shí)。

能避開創(chuàng)建異常的這個(gè)耗時(shí)嗎?答案是可以的,如果在程序中我們不關(guān)心異常拋出的異常占信息,我們可以自己定義一個(gè)異常繼承自已有的異常類型,并寫一個(gè)方法覆蓋掉fillInStackTrace方法就行了。

參考文章

Java異常簡介及其架構(gòu)

關(guān)于異常處理的幾條建議

關(guān)于異常的幾個(gè)謎題(必看)

異常分析初探

透過JVM看Exception本質(zhì)

三言兩語:JVM 字節(jié)碼執(zhí)行實(shí)例分析

文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。

轉(zhuǎn)載請(qǐng)注明本文地址:http://m.specialneedsforspecialkids.com/yun/67207.html

相關(guān)文章

  • Java知識(shí)點(diǎn)匯總

    摘要:由于類型擦除機(jī)制的存在,泛型類中的類型參數(shù)等信息,在運(yùn)行時(shí)刻是不存在的。對(duì)此,對(duì)類文件的格式做了修訂,添加了屬性,用來包含不在類型系統(tǒng)中的類型信息。在運(yùn)行時(shí)刻,會(huì)讀取屬性的內(nèi)容并提供給反射來使用。 OOP 對(duì)象的創(chuàng)建和拷貝 對(duì)象的初始化 多態(tài)的實(shí)現(xiàn) 內(nèi)部類、匿名類、靜態(tài)類 對(duì)象內(nèi)存模型 上面內(nèi)容均請(qǐng)參考以下文章: 談?wù)凧ava的面向?qū)ο?運(yùn)行時(shí) 異常 聊聊Java的異常機(jī)制及實(shí)現(xiàn) ...

    Chao 評(píng)論0 收藏0
  • 聊聊Java泛型實(shí)現(xiàn)

    摘要:靜態(tài)變量是被泛型類的所有實(shí)例所共享的。所以引用能完成泛型類型的檢查。對(duì)于這個(gè)類型系統(tǒng),有如下的一些規(guī)則相同類型參數(shù)的泛型類的關(guān)系取決于泛型類自身的繼承體系結(jié)構(gòu)。事實(shí)上,泛型類擴(kuò)展都不合法。 前言 和C++以模板來實(shí)現(xiàn)靜多態(tài)不同,Java基于運(yùn)行時(shí)支持選擇了泛型,兩者的實(shí)現(xiàn)原理大相庭徑。C++可以支持基本類型作為模板參數(shù),Java卻只能接受類作為泛型參數(shù);Java可以在泛型類的方法中取得...

    lewif 評(píng)論0 收藏0
  • Java面試通關(guān)要點(diǎn)匯總集

    摘要:本文會(huì)以引出問題為主,后面有時(shí)間的話,筆者陸續(xù)會(huì)抽些重要的知識(shí)點(diǎn)進(jìn)行詳細(xì)的剖析與解答。敬請(qǐng)關(guān)注服務(wù)端思維微信公眾號(hào),獲取最新文章。 原文地址:梁桂釗的博客博客地址:http://blog.720ui.com 這里,筆者結(jié)合自己過往的面試經(jīng)驗(yàn),整理了一些核心的知識(shí)清單,幫助讀者更好地回顧與復(fù)習(xí) Java 服務(wù)端核心技術(shù)。本文會(huì)以引出問題為主,后面有時(shí)間的話,筆者陸續(xù)會(huì)抽些重要的知識(shí)點(diǎn)進(jìn)...

    gougoujiang 評(píng)論0 收藏0
  • 聊聊Dubbo - Dubbo可擴(kuò)展機(jī)制實(shí)戰(zhàn)

    摘要:今天我想聊聊的另一個(gè)很棒的特性就是它的可擴(kuò)展性。的擴(kuò)展機(jī)制在的官網(wǎng)上,描述自己是一個(gè)高性能的框架。接下來的章節(jié)中我們會(huì)慢慢揭開擴(kuò)展機(jī)制的神秘面紗。擴(kuò)展擴(kuò)展點(diǎn)的實(shí)現(xiàn)類。的定義在配置文件中可以看到文件中定義了個(gè)的擴(kuò)展實(shí)現(xiàn)。 摘要: 在Dubbo的官網(wǎng)上,Dubbo描述自己是一個(gè)高性能的RPC框架。今天我想聊聊Dubbo的另一個(gè)很棒的特性, 就是它的可擴(kuò)展性。 Dubbo的擴(kuò)展機(jī)制 在Dub...

    techstay 評(píng)論0 收藏0
  • 聊聊Dubbo - Dubbo可擴(kuò)展機(jī)制源碼解析

    摘要:什么是類那什么樣類的才是擴(kuò)展機(jī)制中的類呢類是一個(gè)有復(fù)制構(gòu)造函數(shù)的類,也是典型的裝飾者模式。代碼如下有一個(gè)參數(shù)是的復(fù)制構(gòu)造函數(shù)有一個(gè)構(gòu)造函數(shù),參數(shù)是擴(kuò)展點(diǎn),所以它是一個(gè)擴(kuò)展機(jī)制中的類。 摘要:?在Dubbo可擴(kuò)展機(jī)制實(shí)戰(zhàn)中,我們了解了Dubbo擴(kuò)展機(jī)制的一些概念,初探了Dubbo中LoadBalance的實(shí)現(xiàn),并自己實(shí)現(xiàn)了一個(gè)LoadBalance。是不是覺得Dubbo的擴(kuò)展機(jī)制很不錯(cuò)呀...

    lmxdawn 評(píng)論0 收藏0

發(fā)表評(píng)論

0條評(píng)論

最新活動(dòng)
閱讀需要支付1元查看
<