阿里二面面試題:請(qǐng)你說一下對(duì)受檢異常和非受檢異常的理解?

面試題: 請(qǐng)你說一下對(duì)受檢異常和非受檢異常的理解?

面試考察點(diǎn)

考察目的: 異常的設(shè)計(jì)析珊,在程序開發(fā)中時(shí)非常重要的羡鸥。好的異常設(shè)計(jì)能夠合理清晰的反饋程序的問題,提供排查思路忠寻。同時(shí)惧浴,還能夠很好的處理資源回收問題。所以作為有經(jīng)驗(yàn)的程序員奕剃,必須要了解異常衷旅,以及異常的差異和特性。

考察人群: 工作3年以上纵朋,3年左右一般都會(huì)參與項(xiàng)目中部分核心代碼的編寫柿顶。

背景知識(shí)分享

在Java中,所有的異常都繼承自java.lang.Throwable操软,Throwable有兩個(gè)直接子類嘁锯,Error和Exception,如圖所示聂薪。

image-20211101144642899

Throwable 類是 Java 語(yǔ)言中所有錯(cuò)誤(errors)異常(exceptions)的父類家乘。只有繼承于Throwable類或者其子類的異常才能夠被拋出.

下面分別解釋一下這些異常以及特性。

Error錯(cuò)誤

Error通常是程序無法處理的錯(cuò)誤胆建,這些錯(cuò)誤大多數(shù)與代碼編寫者執(zhí)行的操作無關(guān)烤低,并且它們是無法被捕獲的,因?yàn)樗鼈冊(cè)趹?yīng)用程序的控制和處理能力之外笆载,比如扑馁。

  1. OutOfMemoryError, 內(nèi)存溢出,比較常見的錯(cuò)誤凉驻,是值內(nèi)存空間不足以再提供新對(duì)象的分配腻要。
  2. StackOverflowError,棧溢出涝登。

以下是模擬程序中出現(xiàn)Error問題的例子雄家。

  • 編寫一段使用內(nèi)存存儲(chǔ)的程序

    public class ErrorException {
    
        public static void main(String[] args) {
            List<String> list = new ArrayList<String>();
            /*循環(huán)創(chuàng)建對(duì)象,消耗堆內(nèi)存*/
            for (int i= 0;i < 100000;i++){
                list.add(new String("Hello World"));
            }
        }
    }
    
  • 為了演示OOM錯(cuò)誤胀滚,需要調(diào)整堆內(nèi)存空間大小趟济,添加VM option。

    把堆內(nèi)存空間設(shè)置為1兆咽笼,這個(gè)內(nèi)存空間非常小顷编,所以很容易出現(xiàn)OOM錯(cuò)誤。

    -Xmx1m
    
  • 執(zhí)行上面這段程序剑刑,錯(cuò)誤信息如下.

    錯(cuò)誤信息中描述的是ArrayList在擴(kuò)容時(shí)媳纬,發(fā)現(xiàn)堆內(nèi)存空間不足双肤,所以拋出OOM錯(cuò)誤。

    Exception in thread "main" java.lang.OutOfMemoryError: Java heap space
      at java.util.Arrays.copyOf(Arrays.java:3210)
      at java.util.Arrays.copyOf(Arrays.java:3181)
      at java.util.ArrayList.grow(ArrayList.java:267)
      at java.util.ArrayList.ensureExplicitCapacity(ArrayList.java:241)
      at java.util.ArrayList.ensureCapacityInternal(ArrayList.java:233)
      at java.util.ArrayList.add(ArrayList.java:464)
      at org.example.cl02.ErrorException.main(ErrorException.java:12)
    

在JVM中钮惠,除了程序計(jì)數(shù)器外茅糜,其他區(qū)域:方法區(qū)(Method Area)虛擬機(jī)棧(VM Stack)素挽、本地方法棧(Native Method Stack)堆(Heap) 都是可能發(fā)生OutOfMemoryError錯(cuò)誤蔑赘。

  • 虛擬機(jī)棧:如果線程請(qǐng)求的棧深度大于虛擬機(jī)棧所允許的深度,將會(huì)出現(xiàn)StackOverflowError異常预明;如果虛擬機(jī)動(dòng)態(tài)擴(kuò)展無法申請(qǐng)到足夠的內(nèi)存米死,將出現(xiàn)OutOfMemoryError
  • 本地方法棧和虛擬機(jī)棧一樣贮庞。
  • 堆:Java 堆可以處于物理上不連續(xù)峦筒,邏輯上連續(xù),就像我們的磁盤空間一樣窗慎,如果堆中沒有內(nèi)存完成實(shí)例分配物喷,并且堆無法擴(kuò)展時(shí),將會(huì)拋出 OutOfMemoryError遮斥。
  • 方法區(qū):方法區(qū)無法滿足內(nèi)存分配需求時(shí)峦失,將拋出OutOfMemoryError異常。

出現(xiàn)Error類型的錯(cuò)誤术吗,

Exception

Exception 位于 java.lang 包下尉辑,它是一種頂級(jí)接口,繼承于 Throwable 類较屿,Exception 類及其子類都是 Throwable 的組成條件隧魄。

Exception是運(yùn)行時(shí)的錯(cuò)誤,它通常是程序運(yùn)行時(shí)出現(xiàn)的可以預(yù)料的異常隘蝎,基本上都需要Catch购啄,然后再進(jìn)行相關(guān)處理。

從前面的類關(guān)系圖中可以看到嘱么,Exception有兩類異常的實(shí)現(xiàn)狮含。

  1. RuntimeException,又稱為非受檢異常曼振,這類異常不強(qiáng)制使用Catch捕獲几迄,我們可以根據(jù)實(shí)際場(chǎng)景來判斷是否要Catch。
  2. CheckedException冰评,又稱為受檢異常映胁,這類異常必須顯示地通過Catch捕獲。

受檢異常和非受檢異常

Java規(guī)范中集索,對(duì)非受查異常和受查異常的定義是這樣的:

The unchecked exception classes are the run-time exception classes and the error classes.

The checked exception classes are all exception classes other than the unchecked exception classes. That is, the checked exception classes are Throwable and all its subclasses other than RuntimeException and its subclasses and Errorand its subclasses.

也就是說屿愚,除了 RuntimeException 和其子類,以及error和其子類务荆,其它的所有異常都是 checkedException妆距。

受檢異常的實(shí)例

受檢異常,是值需要顯示通過Catch捕獲的異常函匕,在Java中娱据,除了RuntimeException以外的異常,都屬于受檢異常(checkedException).

我們以NoSuchMethodException為例盅惜,如圖所示中剩,可以明顯看到,該異常在沒有捕獲的情況下抒寂,會(huì)顯示提示語(yǔ)法錯(cuò)誤结啼,有兩個(gè)解決辦法

  1. Add exception to method signature,表示把這個(gè)異常再往上拋屈芜。
  2. Surround with try/catch郊愧,表示使用try/catch捕獲。

![image-20211101164826685](../../../../../../Library/Application Support/typora-user-images/image-20211101164826685.png)

其他常見的受檢異常:

  1. NoSuchFieldException井佑,表示該類沒有指定名稱拋出來的異常属铁。
  2. IllegalAccessException,不允許訪問某個(gè)類的異常躬翁。
  3. ClassNotFoundException焦蘑,類沒有找到拋出異常。
  4. IOException,IO異常盒发。
  5. NumberFormatException例嘱,數(shù)值類型的格式錯(cuò)誤

受檢異常,之所以強(qiáng)制讓開發(fā)者進(jìn)行捕獲宁舰,是因?yàn)檎{(diào)用者接收到該異常時(shí)蝶防,可以清晰的知道哪個(gè)地方出問題了,那么調(diào)用者可以根據(jù)上下文來決定在異常時(shí)做何種處理明吩。

比如IOException间学,出現(xiàn)該異常時(shí),我們可以在Catch中對(duì)流資源進(jìn)行釋放印荔。

非受檢異常實(shí)例

非受檢異常低葫,是指不需要調(diào)用者顯示捕獲的異常,RuntimeException以及其派生類都屬于非受檢異常仍律。

同樣的代碼嘿悬,我們拋出RuntimeException時(shí),并沒有任何語(yǔ)法上的錯(cuò)誤提示水泉。

public class ErrorException {

    public static void main(String[] args) {
        throw new RuntimeException("Occur Exception");
    }
}

常見的非受檢異常有

  1. ArrayIndexOutOfBoundsException善涨,數(shù)組越界異常
  2. NullPointerException窒盐,空指針異常
  3. IllegalArgumentException,非法參數(shù)異常
  4. NegativeArraySizeException钢拧,數(shù)組長(zhǎng)度為負(fù)異常
  5. IllegalStateException蟹漓,非法狀態(tài)異常
  6. ClassCastException,類型轉(zhuǎn)換異常

總結(jié):受檢的異常和非受檢的異常之間最大的區(qū)別在于源内,受檢的異常是由編譯器強(qiáng)制執(zhí)行的葡粒,用于指示不受程序控制的異常情況(例如,I/O 錯(cuò)誤)膜钓,而非受檢的異常在運(yùn)行時(shí)發(fā)生嗽交,用于指示編程錯(cuò)誤(例如,空指針)

Java異常的最佳實(shí)踐

  1. 當(dāng)被調(diào)用的某個(gè)方法服務(wù)執(zhí)行其本身的功能含義是颂斜,可以使用受檢異常夫壁。

  2. 理想情況下,絕對(duì)不應(yīng)將受檢異常用于編程錯(cuò)誤沃疮,在這種情況下掌唾,絕對(duì)不能把資源錯(cuò)誤用于程序流控制。

  3. 盡量不要只捕獲java.lang.Exception這種太過于泛的異常類型忿磅,應(yīng)該要捕獲到具體的錯(cuò)誤類型糯彬。比如InterruptedException,原因有兩個(gè)

    1. 在多人協(xié)作開發(fā)時(shí)葱她,別人可以通過這些代碼很清晰的理解我們的程序撩扒。并且告訴別人更多的信息。
    2. 我們必須要保證程序不會(huì)捕捉到不再我們預(yù)期范圍內(nèi)的異常吨些,比如RuntimeException搓谆,我們希望這類異常是要往外拋,而不是在內(nèi)部被捕獲豪墅。
  4. 不要把異常吞掉泉手,因?yàn)橐坏┏绦虺霈F(xiàn)問題,沒有異常信息很難定位偶器。

  5. 如果希望調(diào)用者能夠從異常中進(jìn)行合理恢復(fù)斩萌,需要設(shè)置為受檢異常類型,如果調(diào)用者無法采用任何措施使得程序無法重異常中恢復(fù)屏轰,需要把該異常設(shè)置為非受檢異常颊郎。

擴(kuò)展:一道經(jīng)典的面試題

一道非常經(jīng)典的面試題,NoClassDefFoundError 和 ClassNotFoundException 有什么區(qū)別霎苗?

  1. NoClassDefFoundError姆吭,表示這個(gè)類在編譯時(shí)期存在,但是在運(yùn)行時(shí)不能找到合適的類導(dǎo)致的錯(cuò)誤唁盏。例如在運(yùn)行時(shí)我們想調(diào)用某個(gè)類的方法或者訪問這個(gè)類的靜態(tài)成員的時(shí)候内狸,發(fā)現(xiàn)這個(gè)類不可用检眯,此時(shí)Java虛擬機(jī)就會(huì)拋出NoClassDefFoundError錯(cuò)誤。

    可能出現(xiàn)的錯(cuò)誤情況如下:

    1. 對(duì)應(yīng)的Class在java的classpath中不可用
    2. 你可能用jar命令運(yùn)行你的程序昆淡,但類并沒有在jar文件的manifest文件中的classpath屬性中定義
    3. 可能程序的啟動(dòng)腳本覆蓋了原來的classpath環(huán)境變量
    4. 因?yàn)镹oClassDefFoundError是java.lang.LinkageError的一個(gè)子類锰瘸,所以可能由于程序依賴的原生的類庫(kù)不可用而導(dǎo)致
    5. 檢查日志文件中是否有java.lang.ExceptionInInitializerError這樣的錯(cuò)誤,NoClassDefFoundError有可能是由于靜態(tài)初始化失敗導(dǎo)致的
    6. 如果你工作在J2EE的環(huán)境瘪撇,有多個(gè)不同的類加載器,也可能導(dǎo)致NoClassDefFoundError
  2. ClassNotFoundException港庄,它是程序運(yùn)行期間的異常倔既,比如當(dāng)我們嘗試在運(yùn)行時(shí)使用反射加載類時(shí),ClassNotFoundException 就會(huì)出現(xiàn)鹏氧。

    @CallerSensitive
    public static Class<?> forName(String className)
      throws ClassNotFoundException {
      Class<?> caller = Reflection.getCallerClass();
      return forName0(className, true, ClassLoader.getClassLoader(caller), caller);
    }
    

總的來說渤涌,ClassNotFoundException 和 NoClassDefFoundError 都是由 CLASSPATH 中缺少類引起的,通常是由于缺少 JAR 文件而引起的把还,但是如果 JVM 認(rèn)為應(yīng)用運(yùn)行時(shí)找不到相應(yīng)的引用实蓬,就會(huì)拋出 NoClassDefFoundError 錯(cuò)誤;當(dāng)你在代碼中顯示的加載類比如 Class.forName() 調(diào)用時(shí)卻沒有找到相應(yīng)的類吊履,就會(huì)拋出 java.lang.ClassNotFoundException安皱。

問題解答

面試題: 請(qǐng)你說一下對(duì)受檢異常和非受檢異常的理解?

回答: 受檢異常和非受檢異常艇炎,都是派生自Throwable這個(gè)類酌伊。他們的區(qū)別是

受檢異常: 是指需要調(diào)用者顯示通過try-catch捕獲的異常

非受檢異常: 是指不需要調(diào)用者顯示捕獲的異常。

之所以要定義受檢異常和非受檢異常缀踪,是因?yàn)樵诔绦蛑芯幼嬖谝恍┬枰脩粼诰幾g期間就去檢查的問題,比如FileNotFoundException驴娃、IOException奏候,這些異常涉及資源處理,調(diào)用者需要捕獲唇敞,其實(shí)它可以提醒開發(fā)者蔗草,如果被調(diào)用的方法出現(xiàn)這類異常時(shí),程序應(yīng)該做好預(yù)判并處理疆柔,比如IOExcetion蕉世,我們需要對(duì)流進(jìn)行關(guān)閉操作。

而非受檢發(fā)生在運(yùn)行期間婆硬,是程序運(yùn)行過程中可能發(fā)生的錯(cuò)誤類型狠轻,比如NullpointExcetpion,這些異常我們可以捕獲彬犯,也可以不捕獲向楼。但是捕獲這些異常只能打印一些日志查吊,除此之外什么都做不了

總結(jié)和思考

關(guān)于異常模型的設(shè)計(jì),有一篇非常好的文章湖蜕。

http://joeduffyblog.com/2016/02/07/the-error-model/

大家有空可以去了解一下逻卖。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市昭抒,隨后出現(xiàn)的幾起案子评也,更是在濱河造成了極大的恐慌,老刑警劉巖灭返,帶你破解...
    沈念sama閱讀 218,451評(píng)論 6 506
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件盗迟,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡熙含,警方通過查閱死者的電腦和手機(jī)罚缕,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,172評(píng)論 3 394
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來怎静,“玉大人邮弹,你說我怎么就攤上這事◎酒福” “怎么了腌乡?”我有些...
    開封第一講書人閱讀 164,782評(píng)論 0 354
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)夜牡。 經(jīng)常有香客問我导饲,道長(zhǎng),這世上最難降的妖魔是什么氯材? 我笑而不...
    開封第一講書人閱讀 58,709評(píng)論 1 294
  • 正文 為了忘掉前任渣锦,我火速辦了婚禮,結(jié)果婚禮上氢哮,老公的妹妹穿的比我還像新娘袋毙。我一直安慰自己,他們只是感情好冗尤,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,733評(píng)論 6 392
  • 文/花漫 我一把揭開白布听盖。 她就那樣靜靜地躺著,像睡著了一般裂七。 火紅的嫁衣襯著肌膚如雪皆看。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,578評(píng)論 1 305
  • 那天背零,我揣著相機(jī)與錄音腰吟,去河邊找鬼。 笑死,一個(gè)胖子當(dāng)著我的面吹牛毛雇,可吹牛的內(nèi)容都是我干的嫉称。 我是一名探鬼主播,決...
    沈念sama閱讀 40,320評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼灵疮,長(zhǎng)吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼织阅!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起震捣,我...
    開封第一講書人閱讀 39,241評(píng)論 0 276
  • 序言:老撾萬榮一對(duì)情侶失蹤荔棉,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后蒿赢,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體润樱,經(jīng)...
    沈念sama閱讀 45,686評(píng)論 1 314
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,878評(píng)論 3 336
  • 正文 我和宋清朗相戀三年诉植,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了祥国。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片昵观。...
    茶點(diǎn)故事閱讀 39,992評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡晾腔,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出啊犬,到底是詐尸還是另有隱情灼擂,我是刑警寧澤,帶...
    沈念sama閱讀 35,715評(píng)論 5 346
  • 正文 年R本政府宣布觉至,位于F島的核電站剔应,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏语御。R本人自食惡果不足惜峻贮,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,336評(píng)論 3 330
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望应闯。 院中可真熱鬧纤控,春花似錦、人聲如沸碉纺。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,912評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)骨田。三九已至耿导,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間态贤,已是汗流浹背舱呻。 一陣腳步聲響...
    開封第一講書人閱讀 33,040評(píng)論 1 270
  • 我被黑心中介騙來泰國(guó)打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留悠汽,地道東北人狮荔。 一個(gè)月前我還...
    沈念sama閱讀 48,173評(píng)論 3 370
  • 正文 我出身青樓胎撇,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親殖氏。 傳聞我的和親對(duì)象是個(gè)殘疾皇子晚树,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,947評(píng)論 2 355

推薦閱讀更多精彩內(nèi)容