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 塊都會始終執行。

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 異常有什麼區別?

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

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

3、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」…
    在這裏插入圖片描述
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章