Java 異常面試問題與解答

Java 提供了一種健壯且面向對象的方法來處理稱爲 Java異常處理的異常狀況。java

1. Java中的異常是什麼?

異常是在程序執行期間可能發生的錯誤事件,它會破壞其正常流程。異常可能源於各類狀況,例如用戶輸入的錯誤數據,硬件故障,網絡鏈接故障等。程序員

每當執行 Java 語句時發生任何錯誤,都會建立一個異常對象,而後 JRE嘗試查找異常處理程序來處理該異常。若是找到了合適的異常處理程序,則將異常對象傳遞處處理程序代碼以處理異常,稱爲捕獲異常。若是未找處處理程序,則應用程序將異常拋出給運行時環境,而且 JRE 終止程序。面試

Java 異常處理框架僅用於處理運行時錯誤,異常處理框架不處理編譯時錯誤。算法

2.Java 中的異常處理關鍵字是什麼?

java 異常處理中使用了四個關鍵字。編程

  1. throw:有時咱們明確地想要建立異常對象,而後將其拋出以中止程序的正常處理。throw 關鍵字用於向運行時拋出異常以進行處理。數組

  2. throws:當咱們在方法中拋出任何已檢查的異常而且不對其進行處理時,咱們須要在方法簽名時使用 throws 關鍵字,以使調用方程序知道該方法可能拋出的異常。調用方方法能夠處理這些異常,也可使用throws關鍵字將其傳播到其調用方方法。咱們能夠在 throws 子句中提供多個異常,它也能夠與 main()方法一塊兒使用。網絡

  3. try-catch:咱們在代碼中使用 try-catch 塊進行異常處理。try 是塊的開始,catch 是 try 塊的末尾,用於處理異常。咱們可使用 try 捕獲多個 catch 塊,而且 try-catch 塊也能夠嵌套。catch 塊須要一個應爲 Exception 類型的參數。框架

  4. finally:finally 塊是可選的,只能與 try-catch 塊一塊兒使用。因爲異常會暫停執行過程,所以咱們可能會打開一些不會關閉的資源,所以可使用 finally 塊。不管是否發生異常,finally 塊都會始終執行。ide

    3.解釋Java異常層次結構?

    Java 異常是分層的,繼承用於對不一樣類型的異常進行分類。Throwable是 Java 異常層次結構的父類,它有兩個子對象– ErrorException。異常進一步分爲檢查異常和運行時異常。函數

Error是超出應用程序範圍的特殊狀況,沒法預見並從中恢復,例如硬件故障,JVM 崩潰或內存不足錯誤。

Checked Exception 是咱們能夠在程序中預期並嘗試從程序中恢復的異常狀況,例如 FileNotFoundException。咱們應該捕獲該異常,並向用戶提供有用的消息,並正確記錄下來以進行調試。Exception是全部 「檢查的異常」 的父類。

Runtime Exception是由錯誤的編程引發的,例如,嘗試從 Array 中檢索元素。在嘗試檢索元素以前,咱們應該首先檢查數組的長度,不然它可能ArrayIndexOutOfBoundException在運行時拋出。RuntimeException是全部運行時異常的父類。

4.Java異常類的重要方法是什麼?

Exception及其全部子類均未提供任何特定方法,而且全部方法均在基類 Throwable 中定義。

  1. String getMessage() –此方法返回 Throwable 消息字符串,而且能夠在經過其構造函數建立異常時提供該消息。
  2. String getLocalizedMessage() –提供此方法,以便子類能夠重寫它以向調用程序提供特定於語言環境的消息。此方法的 Throwable 類實現只需使用getMessage()方法便可返回異常消息。
  3. synchronized Throwable getCause() - 此方法返回異常緣由或 null (緣由未知)。
  4. String toString() –此方法以 String 格式返回有關 Throwable 的信息,返回的 String 包含 Throwable 類的名稱和本地化消息。
  5. void printStackTrace() –此方法將堆棧跟蹤信息打印到標準錯誤流,此方法已重載,咱們能夠傳遞 PrintStream 或 PrintWriter 做爲參數,以將堆棧跟蹤信息寫入文件或流。

    5.解釋 Java 7 ARM Feature和多捕獲塊?

    若是您在單個 try 塊中捕獲了不少異常,則您會注意到 catch 塊代碼看起來很是醜陋,而且主要由用於記錄錯誤的冗餘代碼組成,請記住,Java 7 的功能之一就是多捕獲塊咱們能夠在單個 catch 塊中捕獲多個異常。具備此功能的 catch 塊以下所示:

catch(IOException | SQLException | Exception ex){
     logger.error(ex);
     throw new MyException(ex.getMessage());
}

在大多數狀況下,咱們使用 finally 塊只是爲了關閉資源,有時咱們忘記關閉它們並在資源耗盡時獲取運行時異常。這些異常很難調試,咱們可能須要調查使用該類型資源的每一個位置,以確保咱們將其關閉。所以,java 7 的改進之一是 try-with-resources,咱們能夠在 try 語句自己中建立資源,並在 try-catch 塊內使用它。當執行從 try-catch 塊執行時,運行時環境會自動關閉這些資源。具備這種改進的 try-catch 塊示例爲:

try (MyResource mr = new MyResource()) {
    System.out.println("MyResource created in try-with-resources");
} catch (Exception e) {
    e.printStackTrace();
}

6.Java中的 Checked 和 Unchecked 異常有什麼區別?

一、檢查異常應在代碼中使用 try-catch 塊進行處理,不然方法應使用 throws 關鍵字使調用者知道該方法可能拋出的檢查異常。未經檢查的異常不須要在程序中處理,也不須要在方法的 throws 子句中說起。

2.、Exception是全部Checked 異常的超類,而RuntimeException是全部Unchecked 的異常的超類。請注意,RuntimeException 是 Exception 的子類。

三、Checked 異常是須要在代碼中處理的錯誤方案,不然您將得到編譯時錯誤。例如,若是您使用 FileReader 讀取文件,則可能會拋出該文件FileNotFoundException,咱們必須將其在 try-catch 塊中捕獲,或再次將其拋出給調用方方法。Unchecked 異常一般是由不良的編程引發的,例如,在調用對象引用中的方法而不確保其不爲 null 時,會引起 NullPointerException。例如,我能夠編寫一種方法來刪除字符串中的全部元音。確保不傳遞空字符串對象是調用者的責任。我可能會更改處理這些狀況的方法,但理想狀況下,調用方應注意這一點。

7.Java中 throw 和 throws 之間的區別是什麼?

throws 關鍵字與方法一塊兒使用,以聲明該方法可能拋出的異常,而 throw 關鍵字用於中斷程序流,並將異常對象移交給運行時進行處理。

8.如何用 Java 編寫自定義異常?

咱們能夠擴展Exception類或它的任何子類來建立咱們的自定義異常類。自定義異常類能夠具備本身的變量和方法,可用於將錯誤代碼或其餘與異常相關的信息傳遞給異常處理程序。

自定義異常的一個簡單示例以下所示。

package com.journaldev.exceptions;

import java.io.IOException;

public class MyException extends IOException {

    private static final long serialVersionUID = 4664456874499611218L;
    
    private String errorCode="Unknown_Exception";
    
    public MyException(String message, String errorCode){
        super(message);
        this.errorCode=errorCode;
    }
    
    public String getErrorCode(){
        return this.errorCode;
    }
    

}

9.什麼是 Java 中的 OutOfMemoryError?

Java 中的 OutOfMemoryError 是 java.lang.VirtualMachineError 的子類,當 JVM 堆內存不足時,它會被 JVM 拋出。咱們能夠經過修改 java 選項提供更多內存來解決此錯誤。

$>java MyProgram -Xms1024m -Xmx1024m -XX:PermSize=64M -XX:MaxPermSize=256m

10.有哪些不一樣的狀況致使 「主線程異常」?

一些常見的主線程異常狀況是:

  • main 線程中的 java.lang.UnsupportedClassVersionError 異常:當您的 Java 類是從另外一個 JDK 版本編譯的,而您試圖從另外一個 Java 版本運行它時,將發生此異常。
  • main 線程中的 java.lang.NoClassDefFoundError 異常:此異常有兩種變體。第一個是您以. class 擴展名提供類全名的位置。第二種狀況是找不到類時。
  • main 線程中的 java.lang.NoSuchMethodError 異常:當您嘗試運行不具備 main 方法的類時,將發生此異常。
  • main 線程中的 java.lang.ArithmeticException 異常:每當從 main 方法拋出任何異常時,它都會打印控制檯異常。第一部分說明從 main 方法拋出異常,第二部分打印異常類名稱,而後在冒號後打印異常消息。

11.Java中的 final,finally 和 finalize 有什麼區別?

final 和 finally 是 Java 中的關鍵字,而 finalize 是一種方法。

  • final 關鍵字能夠與類變量一塊兒使用,以使它們不能被從新分配; class 能夠避免經過類進行擴展; final
    關鍵字能夠與方法避免被子類覆蓋;

  • finally 關鍵字能夠與 try-catch 塊一塊兒使用,以提供將始終執行的語句即便出現某些異常,一般最終仍是會用來關閉資源。

  • finalize()方法在對象被銷燬以前由垃圾回收器執行,這是確保關閉全部全局資源的好方法。

在這三個中,只有finally 與 Java 異常處理有關。

12.當 main 方法拋出異常時會發生什麼?

當 main()方法引起異常時,Java Runtime 將終止程序並在系統控制檯中打印異常消息和堆棧跟蹤。

13.咱們能夠有一個空的捕獲塊嗎?

咱們能夠有一個空的 catch 塊,但這是最糟糕的編程示例。咱們永遠不該該有空的 catch 塊,由於若是異常被該塊捕獲,咱們將沒有有關該異常的信息,調試它將是一場噩夢。至少應該有一條日誌記錄語句,以將異常詳細信息記錄在控制檯或日誌文件中。

14.提供一些 Java 異常處理最佳實踐嗎?

與 Java 異常處理有關的一些最佳實踐是:

  • 捕獲特定異常能夠簡化調試。
  • 在程序中儘早拋出異常(Fast-Fast)。
  • 在程序後期捕獲異常,讓調用者處理異常。
  • 使用 Java 7 ARM 功能來確保資源被關閉,或者使用 finally 塊來正確地關閉它們。
  • 始終記錄異常消息以進行調試。
  • 使用多捕獲塊讓代碼更加清潔。
  • 使用自定義異常能夠從應用程序 API 中引起單一類型的異常。
  • 遵循命名約定,始終以 Exception 結尾。
  • 使用 javadoc 中的 @throws 記錄由方法引起的異常。
  • 異常的代價很高,所以僅在有意義時才拋出異常。不然,您能夠捕獲它們並返回null或不響應。

15.如下程序有什麼問題,咱們該如何解決?

在這裏,咱們將研究與 Java 異常相關的一些編程問題。

1). 下面的程序有什麼問題?

package com.journaldev.exceptions;

import java.io.FileNotFoundException;
import java.io.IOException;

public class TestException {

    public static void main(String[] args) {
        try {
            testExceptions();
        } catch (FileNotFoundException | IOException e) {
            e.printStackTrace();
        }
    }

    public static void testExceptions() throws IOException, FileNotFoundException{
        
    }
}

上面的程序沒法編譯,而且您會收到錯誤消息,「The exception FileNotFoundException is already caught by the alternative IOException」。這是由於 FileNotFoundException 是 IOException 的子類,有兩種方法能夠解決此問題。

第一種方法是對兩個異常都使用單個 catch 塊。

try {
    testExceptions();
}catch(FileNotFoundException e){
    e.printStackTrace();
}catch (IOException  e) {
    e.printStackTrace();
}

另外一種方法是從多捕獲塊中刪除 FileNotFoundException。

try {
    testExceptions();
}catch (IOException  e) {
    e.printStackTrace();
}

您能夠根據狀況選擇任何一種方法。

2). 下面的程序有什麼問題?

package com.journaldev.exceptions;

import java.io.FileNotFoundException;
import java.io.IOException;

import javax.xml.bind.JAXBException;

public class TestException1 {

    public static void main(String[] args) {
            try {
                go();
            } catch (IOException e) {
                e.printStackTrace();
            } catch (FileNotFoundException e) {
                e.printStackTrace();
            } catch (JAXBException e) {
                e.printStackTrace();
            }
    }

    public static void go() throws IOException, JAXBException, FileNotFoundException{
        
    }
}

該程序將編譯錯誤,由於 FileNotFoundException 是 IOException 的子類,所以 FileNotFoundException 的 catch 塊不可訪問,而且您將收到錯誤消息 「 Unreachable catch block for FileNotFoundException. It is already handled by the catch block for IOException」。

您須要修復 catch 塊順序才能解決此問題。

try {
    go();
} catch (FileNotFoundException e) {
    e.printStackTrace();
} catch (IOException e) {
    e.printStackTrace();
} catch (JAXBException e) {
    e.printStackTrace();
}

請注意,JAXBException 與 IOException 或 FileNotFoundException 不相關,能夠放置在以上 catch 塊層次結構中的任何位置。

3). 下面的程序有什麼問題?

package com.journaldev.exceptions;

import java.io.IOException;

import javax.xml.bind.JAXBException;

public class TestException2 {

    public static void main(String[] args) {
        try {
            foo();
        } catch (IOException e) {
            e.printStackTrace();
        }catch(JAXBException e){
            e.printStackTrace();
        }catch(NullPointerException e){
            e.printStackTrace();
        }catch(Exception e){
            e.printStackTrace();
        }
    }

    public static void foo() throws IOException{
        
    }
}

該程序將沒法編譯,由於 JAXBException 是一個已檢查的異常,而且 foo()方法應拋出此異常以捕獲調用方法。您將收到錯誤消息 「 JAXBException 沒法訪問的捕獲塊。不會從 try 語句主體中引起此異常。

要解決此問題,您將必須刪除 JAXBException 的 catch 塊。

注意,捕獲 NullPointerException 是有效的,由於它是未經檢查的異常。

4). 下面的程序有什麼問題?

package com.journaldev.exceptions;

public class TestException3 {

    public static void main(String[] args) {
        try{
        bar();
        }catch(NullPointerException e){
            e.printStackTrace();
        }catch(Exception e){
            e.printStackTrace();
        }
        
        foo();
    }

    public static void bar(){
        
    }

    public static void foo() throws NullPointerException{
        
    }
}

這是一個技巧性的問題,代碼沒有問題,它將成功編譯。咱們老是能夠捕獲 Exception 或任何未經檢查的異常,即便它不在方法的 throws 子句中也是如此。

一樣,若是方法(foo)在 throws 子句中聲明未經檢查的異常,則在程序中處理該異常不是強制性的。

5). 下面的程序有什麼問題?

package com.journaldev.exceptions;

import java.io.IOException;

public class TestException4 {

    public void start() throws IOException{     
    }

    public void foo() throws NullPointerException{
        
    }
    }

    class TestException5 extends TestException4{

    public void start() throws Exception{
    }

    public void foo() throws RuntimeException{
        
    }
}

上面的程序沒法編譯,由於子類中的start()方法簽名不一樣。要解決此問題,咱們能夠將子類中的方法特性更改成與超類徹底相同,也能夠從子類方法中刪除throws子句,以下所示。

@Override
public void start(){
}

6). 下面的程序有什麼問題?

package com.journaldev.exceptions;

import java.io.IOException;

import javax.xml.bind.JAXBException;

public class TestException6 {

    public static void main(String[] args) {
        try {
            foo();
        } catch (IOException | JAXBException e) {
            e = new Exception("");
            e.printStackTrace();
        }catch(Exception e){
            e = new Exception("");
            e.printStackTrace();
        }
    }

    public static void foo() throws IOException, JAXBException{
        
    }
}

上面的程序沒法編譯,由於多捕獲塊中的異常對象是最終對象,咱們沒法更改其值。因爲「沒法分配多捕獲塊的參數e」,將致使編譯時錯誤。

咱們必須刪除對新異常對象的「 e」分配以解決此錯誤。


「不積跬步,無以致千里」,但願將來的你能:有夢爲馬 隨處可棲!加油,少年!

關注公衆號:「Java 知己」,天天更新Java知識哦,期待你的到來!

  • 發送「Group」,與 10 萬程序員一塊兒進步。
  • 發送「面試」,領取BATJ面試資料、面試視頻攻略。
  • 發送「玩轉算法」,領取《玩轉算法》系列視頻教程。
  • 千萬不要發送「1024」...
相關文章
相關標籤/搜索