Java 異常面試問題與解答

Java 提供了一種健壯且面向?qū)ο蟮姆椒▉硖幚矸Q為 Java異常處理的異常情況。

1. Java中的異常是什么?

異常是在程序執(zhí)行期間可能發(fā)生的錯(cuò)誤事件,它會破壞其正常流程。異常可能源于各種情況,例如用戶輸入的錯(cuò)誤數(shù)據(jù),硬件故障,網(wǎng)絡(luò)連接故障等。

每當(dāng)執(zhí)行 Java 語句時(shí)發(fā)生任何錯(cuò)誤,都會創(chuàng)建一個(gè)異常對象,然后 JRE嘗試查找異常處理程序來處理該異常。如果找到了合適的異常處理程序,則將異常對象傳遞到處理程序代碼以處理異常,稱為捕獲異常。如果未找到處理程序,則應(yīng)用程序?qū)惓伋鼋o運(yùn)行時(shí)環(huán)境,并且 JRE 終止程序。

Java 異常處理框架僅用于處理運(yùn)行時(shí)錯(cuò)誤,異常處理框架不處理編譯時(shí)錯(cuò)誤。

2.Java 中的異常處理關(guān)鍵字是什么?

java 異常處理中使用了四個(gè)關(guān)鍵字。

  1. throw:有時(shí)我們明確地想要?jiǎng)?chuàng)建異常對象,然后將其拋出以停止程序的正常處理。throw 關(guān)鍵字用于向運(yùn)行時(shí)拋出異常以進(jìn)行處理。

  2. throws:當(dāng)我們在方法中拋出任何已檢查的異常并且不對其進(jìn)行處理時(shí),我們需要在方法簽名時(shí)使用 throws 關(guān)鍵字,以使調(diào)用方程序知道該方法可能拋出的異常。調(diào)用方方法可以處理這些異常,也可以使用throws關(guān)鍵字將其傳播到其調(diào)用方方法。我們可以在 throws 子句中提供多個(gè)異常,它也可以與 main()方法一起使用。

  3. try-catch:我們在代碼中使用 try-catch 塊進(jìn)行異常處理。try 是塊的開始,catch 是 try 塊的末尾,用于處理異常。我們可以使用 try 捕獲多個(gè) catch 塊,并且 try-catch 塊也可以嵌套。catch 塊需要一個(gè)應(yīng)為 Exception 類型的參數(shù)。

  4. finally:finally 塊是可選的,只能與 try-catch 塊一起使用。由于異常會暫停執(zhí)行過程,因此我們可能會打開一些不會關(guān)閉的資源,因此可以使用 finally 塊。無論是否發(fā)生異常,finally 塊都會始終執(zhí)行。

3.解釋Java異常層次結(jié)構(gòu)?

Java 異常是分層的,繼承用于對不同類型的異常進(jìn)行分類。Throwable是 Java 異常層次結(jié)構(gòu)的父類,它有兩個(gè)子對象– ErrorException。異常進(jìn)一步分為檢查異常和運(yùn)行時(shí)異常。

Error是超出應(yīng)用程序范圍的特殊情況,無法預(yù)見并從中恢復(fù),例如硬件故障,JVM 崩潰或內(nèi)存不足錯(cuò)誤。

Checked Exception 是我們可以在程序中預(yù)期并嘗試從程序中恢復(fù)的異常情況,例如 FileNotFoundException。我們應(yīng)該捕獲該異常,并向用戶提供有用的消息,并正確記錄下來以進(jìn)行調(diào)試。Exception是所有 “檢查的異?!?的父類。

Runtime Exception是由錯(cuò)誤的編程引起的,例如,嘗試從 Array 中檢索元素。在嘗試檢索元素之前,我們應(yīng)該首先檢查數(shù)組的長度,否則它可能ArrayIndexOutOfBoundException在運(yùn)行時(shí)拋出。RuntimeException是所有運(yùn)行時(shí)異常的父類。

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

Exception及其所有子類均未提供任何特定方法,并且所有方法均在基類 Throwable 中定義。

  1. String getMessage() –此方法返回 Throwable 消息字符串,并且可以在通過其構(gòu)造函數(shù)創(chuàng)建異常時(shí)提供該消息。
  2. String getLocalizedMessage() –提供此方法,以便子類可以重寫它以向調(diào)用程序提供特定于語言環(huán)境的消息。此方法的 Throwable 類實(shí)現(xiàn)只需使用getMessage()方法即可返回異常消息。
  3. synchronized Throwable getCause() - 此方法返回異常原因或 null (原因未知)。
  4. String toString() –此方法以 String 格式返回有關(guān) Throwable 的信息,返回的 String 包含 Throwable 類的名稱和本地化消息。
  5. void printStackTrace() –此方法將堆棧跟蹤信息打印到標(biāo)準(zhǔn)錯(cuò)誤流,此方法已重載,我們可以傳遞 PrintStream 或 PrintWriter 作為參數(shù),以將堆棧跟蹤信息寫入文件或流。

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

如果您在單個(gè) try 塊中捕獲了很多異常,則您會注意到 catch 塊代碼看起來非常丑陋,并且主要由用于記錄錯(cuò)誤的冗余代碼組成,請記住,Java 7 的功能之一就是多捕獲塊我們可以在單個(gè) catch 塊中捕獲多個(gè)異常。具有此功能的 catch 塊如下所示:

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

在大多數(shù)情況下,我們使用 finally 塊只是為了關(guān)閉資源,有時(shí)我們忘記關(guān)閉它們并在資源耗盡時(shí)獲取運(yùn)行時(shí)異常。這些異常很難調(diào)試,我們可能需要調(diào)查使用該類型資源的每個(gè)位置,以確保我們將其關(guān)閉。因此,java 7 的改進(jìn)之一是 try-with-resources,我們可以在 try 語句本身中創(chuàng)建資源,并在 try-catch 塊內(nèi)使用它。當(dāng)執(zhí)行從 try-catch 塊執(zhí)行時(shí),運(yùn)行時(shí)環(huán)境會自動(dòng)關(guān)閉這些資源。具有這種改進(jìn)的 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 異常有什么區(qū)別?

1、檢查異常應(yīng)在代碼中使用 try-catch 塊進(jìn)行處理,否則方法應(yīng)使用 throws 關(guān)鍵字使調(diào)用者知道該方法可能拋出的檢查異常。未經(jīng)檢查的異常不需要在程序中處理,也不需要在方法的 throws 子句中提及。

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

3、Checked 異常是需要在代碼中處理的錯(cuò)誤方案,否則您將獲得編譯時(shí)錯(cuò)誤。例如,如果您使用 FileReader 讀取文件,則可能會拋出該文件FileNotFoundException,我們必須將其在 try-catch 塊中捕獲,或再次將其拋出給調(diào)用方方法。Unchecked 異常通常是由不良的編程引起的,例如,在調(diào)用對象引用中的方法而不確保其不為 null 時(shí),會引發(fā) NullPointerException。例如,我可以編寫一種方法來刪除字符串中的所有元音。確保不傳遞空字符串對象是調(diào)用者的責(zé)任。我可能會更改處理這些情況的方法,但理想情況下,調(diào)用方應(yīng)注意這一點(diǎn)。

7.Java中 throw 和 throws 之間的區(qū)別是什么?

throws 關(guān)鍵字與方法一起使用,以聲明該方法可能拋出的異常,而 throw 關(guān)鍵字用于中斷程序流,并將異常對象移交給運(yùn)行時(shí)進(jìn)行處理。

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

我們可以擴(kuò)展Exception類或它的任何子類來創(chuàng)建我們的自定義異常類。自定義異常類可以具有自己的變量和方法,可用于將錯(cuò)誤代碼或其他與異常相關(guān)的信息傳遞給異常處理程序。

自定義異常的一個(gè)簡單示例如下所示。

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 的子類,當(dāng) JVM 堆內(nèi)存不足時(shí),它會被 JVM 拋出。我們可以通過修改 java 選項(xiàng)提供更多內(nèi)存來解決此錯(cuò)誤。

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

10.有哪些不同的情況導(dǎo)致 “主線程異常”?

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

  • main 線程中的 java.lang.UnsupportedClassVersionError 異常:當(dāng)您的 Java 類是從另一個(gè) JDK 版本編譯的,而您試圖從另一個(gè) Java 版本運(yùn)行它時(shí),將發(fā)生此異常。
  • main 線程中的 java.lang.NoClassDefFoundError 異常:此異常有兩種變體。第一個(gè)是您以. class 擴(kuò)展名提供類全名的位置。第二種情況是找不到類時(shí)。
  • main 線程中的 java.lang.NoSuchMethodError 異常:當(dāng)您嘗試運(yùn)行不具有 main 方法的類時(shí),將發(fā)生此異常。
  • main 線程中的 java.lang.ArithmeticException 異常:每當(dāng)從 main 方法拋出任何異常時(shí),它都會打印控制臺異常。第一部分說明從 main 方法拋出異常,第二部分打印異常類名稱,然后在冒號后打印異常消息。

11.Java中的 final,finally 和 finalize 有什么區(qū)別?

final 和 finally 是 Java 中的關(guān)鍵字,而 finalize 是一種方法。

  • final 關(guān)鍵字可以與類變量一起使用,以使它們不能被重新分配; class 可以避免通過類進(jìn)行擴(kuò)展; final
    關(guān)鍵字可以與方法避免被子類覆蓋;

  • finally 關(guān)鍵字可以與 try-catch 塊一起使用,以提供將始終執(zhí)行的語句即使出現(xiàn)某些異常,通常最終還是會用來關(guān)閉資源。

  • finalize()方法在對象被銷毀之前由垃圾回收器執(zhí)行,這是確保關(guān)閉所有全局資源的好方法。

在這三個(gè)中,只有finally 與 Java 異常處理有關(guān)。

12.當(dāng) main 方法拋出異常時(shí)會發(fā)生什么?

當(dāng) main()方法引發(fā)異常時(shí),Java Runtime 將終止程序并在系統(tǒng)控制臺中打印異常消息和堆棧跟蹤。

13.我們可以有一個(gè)空的捕獲塊嗎?

我們可以有一個(gè)空的 catch 塊,但這是最糟糕的編程示例。我們永遠(yuǎn)不應(yīng)該有空的 catch 塊,因?yàn)槿绻惓1辉搲K捕獲,我們將沒有有關(guān)該異常的信息,調(diào)試它將是一場噩夢。至少應(yīng)該有一條日志記錄語句,以將異常詳細(xì)信息記錄在控制臺或日志文件中。

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

與 Java 異常處理有關(guān)的一些最佳實(shí)踐是:

  • 捕獲特定異??梢院喕{(diào)試。
  • 在程序中盡早拋出異常(Fast-Fast)。
  • 在程序后期捕獲異常,讓調(diào)用者處理異常。
  • 使用 Java 7 ARM 功能來確保資源被關(guān)閉,或者使用 finally 塊來正確地關(guān)閉它們。
  • 始終記錄異常消息以進(jìn)行調(diào)試。
  • 使用多捕獲塊讓代碼更加清潔。
  • 使用自定義異常可以從應(yīng)用程序 API 中引發(fā)單一類型的異常。
  • 遵循命名約定,始終以 Exception 結(jié)尾。
  • 使用 javadoc 中的 @throws 記錄由方法引發(fā)的異常。
  • 異常的代價(jià)很高,因此僅在有意義時(shí)才拋出異常。否則,您可以捕獲它們并返回null或不響應(yīng)。

15.以下程序有什么問題,我們該如何解決?

在這里,我們將研究與 Java 異常相關(guān)的一些編程問題。

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{
        
    }
}

上面的程序無法編譯,并且您會收到錯(cuò)誤消息,“The exception FileNotFoundException is already caught by the alternative IOException”。這是因?yàn)?FileNotFoundException 是 IOException 的子類,有兩種方法可以解決此問題。

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

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

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

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

您可以根據(jù)情況選擇任何一種方法。

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{
        
    }
}

該程序?qū)⒕幾g錯(cuò)誤,因?yàn)?FileNotFoundException 是 IOException 的子類,因此 FileNotFoundException 的 catch 塊不可訪問,并且您將收到錯(cuò)誤消息 “ Unreachable catch block for FileNotFoundException. It is already handled by the catch block for IOException”。

您需要修復(fù) catch 塊順序才能解決此問題。

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

請注意,JAXBException 與 IOException 或 FileNotFoundException 不相關(guān),可以放置在以上 catch 塊層次結(jié)構(gòu)中的任何位置。

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{
        
    }
}

該程序?qū)o法編譯,因?yàn)?JAXBException 是一個(gè)已檢查的異常,并且 foo()方法應(yīng)拋出此異常以捕獲調(diào)用方法。您將收到錯(cuò)誤消息 “ JAXBException 無法訪問的捕獲塊。不會從 try 語句主體中引發(fā)此異常。

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

注意,捕獲 NullPointerException 是有效的,因?yàn)樗俏唇?jīng)檢查的異常。

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{
        
    }
}

這是一個(gè)技巧性的問題,代碼沒有問題,它將成功編譯。我們總是可以捕獲 Exception 或任何未經(jīng)檢查的異常,即使它不在方法的 throws 子句中也是如此。

同樣,如果方法(foo)在 throws 子句中聲明未經(jīng)檢查的異常,則在程序中處理該異常不是強(qiáng)制性的。

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{
        
    }
}

上面的程序無法編譯,因?yàn)樽宇愔械膕tart()方法簽名不同。要解決此問題,我們可以將子類中的方法特性更改為與超類完全相同,也可以從子類方法中刪除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{
        
    }
}

上面的程序無法編譯,因?yàn)槎嗖东@塊中的異常對象是最終對象,我們無法更改其值。由于“無法分配多捕獲塊的參數(shù)e”,將導(dǎo)致編譯時(shí)錯(cuò)誤。

我們必須刪除對新異常對象的“ e”分配以解決此錯(cuò)誤。


“不積跬步,無以至千里”,希望未來的你能:有夢為馬 隨處可棲!加油,少年!

關(guān)注公眾號:「Java 知己」,每天更新Java知識哦,期待你的到來!

  • 發(fā)送「Group」,與 10 萬程序員一起進(jìn)步。
  • 發(fā)送「面試」,領(lǐng)取BATJ面試資料、面試視頻攻略。
  • 發(fā)送「玩轉(zhuǎn)算法」,領(lǐng)取《玩轉(zhuǎn)算法》系列視頻教程。
  • 千萬不要發(fā)送「1024」...
    每日福利
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容