Java面試中異常常見問題

Java的異常機制(概念)

Java語言中的異常處理包括的四個環節。

  • 聲明異常
    throws關鍵字可以在方法上聲明該方法要拋出的異常,然後在方法內部通過throw拋出異常對象。
  • 拋出異常
    throw用於拋出異常。
  • 捕獲異常
    try是用於檢測被包住的語句塊是否出現異常,如果有異常,則拋出異常,並執行catch語句。
  • 處理異常
    cacth用於捕獲從try中拋出的異常並作出處理。
    finally語句塊是不管有沒有出現異常都要執行的內容。

簡述Java中的異常處理機制的簡單原理和應用。

異常是指java程序運行時(非編譯)所發生的非正常情況或錯誤, Java使用面向對象的方式來處理異常, 它把程序中發生的每個異常也都分別封裝到一個對象來表示,該對象中包含有異常的信息。

虛擬機必須宕機的錯誤屬於error,程序可以死掉也可以不死掉的錯誤屬於系統異常,程序不應該死掉的錯誤屬於普通異常;

Java對異常進行了分類,不同類型的異常分別用不同的Java類表示,所有異常的根類爲java.lang.Throwable,下面又派生了兩個子類:Error和Exception;

Error表示應用程序本身無法克服和恢復的一種嚴重問題,程序只有死的份了, 例如,說內存溢出和線程死鎖等系統問題。

Exception表示程序還能夠克服和恢復的問題,其中又分爲系統異常(運行時異常,非檢查)和普通異常(檢查);
系統異常是軟件本身缺陷所導致的問題,也就是軟件開發人員考慮不周所導致的問題,軟件使用者無法克服和恢復這種問題,但在這種問題下還可以讓軟件系統繼續運行或者讓軟件死掉,例如,數組腳本越界(ArrayIndexOutOfBoundsException),空指針異常(NullPointerException)、類轉換異常(ClassCastException);

普通異常是運行環境的變化或異常所導致的問題,是用戶能夠克服的問題,例如,網絡斷線,硬盤空間不夠,IO異常,以及SQL異常發生這樣的異常後,程序不應該死掉。

java爲系統異常和普通異常提供了不同的解決方案,編譯器強制普通異常必須try..catch處理或用throws聲明繼續拋給上層調用方法處理,所以普通異常也稱爲checked異常,checked 異常也就是我們經常遇到的IO異常,以及SQL異常都是這種異常。對於這種異常,JAVA編譯器強制要求我們必需對出現的這些異常進行catch。因爲普通異常和運行環境有關係,具客觀性,不可決定性和不可預測性!必須捕獲或者拋給上層。而系統異常(也叫rutime exception)可以處理也可以不處理,所以編譯器不強制用try..catch處理或用throws聲明,所以系統異常也稱爲unchecked異常

error和exception有什麼區別?

Error指程序本身不能恢復和克服的一種嚴重問題。比如說內存溢出,線程死鎖。不可能指望程序能處理這樣的情況。

Exception指軟件本身設計的問題(系統異常也叫運行時,使用者無法克服)或運行環境變化導致的問題(普通異常也叫檢查異常,使用者可以克服),程序本身能恢復和克服。也就是說它表示如果程序運行正常,從不會發生的情況。

運行時異常與一般異常有何異同?

異常表示程序運行過程中可能出現的非正常狀態,運行時異常(也叫非檢查異常)表示虛擬機的通常操作中可能遇到的異常,是一種常見運行錯誤。javac要求方法必須聲明,拋出可能發生的非運行時異常,但是並不要求必須聲明拋出未被捕獲的運行時異常。

異常相關問題

try-finally中return問題

public class TryReturn1 {
    public static void main(String[] args) {
        System.out.println(get());
    }
    public static int get() {
        try {
            return 1;
        } finally {
            return 2;
        }
    }
}

輸出:2
分析:
在一個try-finally 語句中,finally 語句塊總是在控制權離開try 語句塊時執行的,但是finally中如果有return則try中的return結果不再返回給主調者。
即,如果finally裏也有返回語句,那麼以finally的爲主。也就是說,千萬不要用一個return、break、continue 或throw 來退出一個finally 語句塊,且千萬不要允許將一個受檢查的異常傳播到一個finally 語句塊之外去。容易出一些潛在bug。

public class TryReturn2 {
    public static void main(String[] args) {
        System.out.println(get());
    }
    public static int get() {
        int x = 1;
        try {
            return x;
        } finally {
            ++x;
        }
    }
}

輸出:1
分析:
執行try時,遇到return語句,且還有finally語句塊,那麼程序此時一定要到finally執行,但是在轉去finally語句塊之前,try中先把要返回的結果(雖然準備好了返回值,但是還沒返回呢,所以我說是執行的中間)存放到不同於X的局部變量中,執行完finally後,在從局部變量中取出原返回結果,因此,即使finally中對變量x進行了改變,但是不會影響返回結果。因爲方法內使用棧保存返回值。

try-finally-exit問題

public class TryExit {
    public static void main(String[] args) {
        try {
            System.out.println("Hello world");
            System.exit(0);
        } catch (Exception e) {
            System.out.println("Goodbye world");
        }
    }
}

輸出:Hello world
分析:System.exit 將立即停止所有的線程,它並不會使finally 語句塊得到調用,但是它在停止VM 之前會執行關閉掛鉤操作。當VM 被關閉時,請使用關閉掛鉤來終止外部資源。通過調用System.halt 可以在不執行關閉掛鉤的情況下停止VM,但是這個方法很少使用。

try-catch問題

 public static void foo() {
        try {
            System.out.println("Hello,World!");
        } catch (IOException e) {
            System.out.println("Exception!");
        }
    }

這段代碼編譯通不過,因爲println()並不拋出異常。Java語言規範中描述道:如果一個catch 子句要捕獲一個類型爲 E 的被檢查異常,而其相對應的try 子句如不能拋出E 的某種子類型的異常,那麼這就是一個編譯期錯誤。

 public static void bar() {
        try {
        } catch (Exception e) {
            System.out.println("Exception!");
        }
    }

這段代碼編譯可以編譯通過,並且輸出:Exception!
分析:catch 子句檢查了Exception,捕獲 Exception 或 Throwble 的 catch 子句是合法的,不管與其相對應的 try 子句的內容爲何。

總結

關於Java異常這一方面暫時就總結這些內容了,如果有好問題會繼續補充的。

注:本文轉載自Core Java 經典筆試題總結(異常類問題)

發佈了97 篇原創文章 · 獲贊 125 · 訪問量 30萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章