JavaRush /Java Blog /Random-TW /喝咖啡休息#220。如何修復 Java 中的異常 - 詳細指南

喝咖啡休息#220。如何修復 Java 中的異常 - 詳細指南

在 Random-TW 群組發布
來源:JavaTechOnline 本教學將幫助您學習如何修復 Java 中的常見異常。除了理論之外,您還將看到解決此類問題的程式碼範例。 喝咖啡休息#220。 如何修復 Java 中的異常 - 詳細指南 - 1與其他程式語言一樣,Java 開發人員在編寫程式碼時可能會遇到錯誤或異常。應認真對待異常情況,因為異常情況的發生會佔用工作時間。然而,只要掌握一點知識,您就可以加快解決大多數此類問題的速度。那麼,讓我們學習如何修復 Java 中的常見異常。

Java 中避免異常的一般準則

為了避免在 Java 中引發任何異常,理解並遵循編碼指南非常重要:
  1. 在程式碼中使用使用者輸入之前,請務必驗證使用者輸入。
  2. 使用try-catchthrowsthrow block ,取決於適合特定場景的內容。
  3. 不要忽略程式碼中有關處理和錯誤的訊息。這將有助於識別和糾正問題。
  4. 請務必記錄異常以進行調試。您可以使用記錄器訊息來幫助識別問題。
  5. 遵循編碼最佳實踐以避免異常並徹底測試您的程式碼。
  6. 更新您的 API 依賴項,以確保您使用最新、最穩定版本的程式庫和框架。
  7. 使用必要的工具和測試框架在程式碼引發異常之前識別程式碼中的潛在問題。
  8. 監控應用程式的效能和日誌,以快速識別和解決任何問題。
  9. 隨時了解最新的安全最佳實踐,以確保您的程式碼安全並免受任何潛在的攻擊。
  10. 徹底記錄您的程式碼及其異常,以便其他開發人員更容易理解和維護。

Java 中最常見的異常列表

Java 有一個相當長的異常列表。讓我們來看看一些最常見的:

空指針異常

NullPointerException是一種RuntimeException異常。當我們嘗試使用具有空值的引用變數時,就會發生這種情況。這意味著它指向一個值為null的物件或變數。當我們嘗試呼叫方法或存取尚未初始化的物件的欄位時,或者當我們將null作為參數傳遞給不處理它的方法時,可能會發生此類錯誤。若要防止引發NullPointerException,可以使用==運算子檢查引用變數是否為 null 。如果是這種情況,則需要正確處理 null 情況。或者,我們可以將變數初始化為預設值(如果可能),以確保我們永遠不會遇到空引用。避免NullPointerException 的另一種方法是使用Optional類別。在 Java 中,Optional是一個容器對象,可能包含或不包含非空值。它用於表示值是否存在,類似於使用 null 值表示值不存在。如果程式設計師嘗試存取Optional物件的空值,程式將不會拋出NullPointerException,而是傳回一個空的Optional物件。換句話說,Optional 強製程式設計師處理值遺失的情況,這有助於避免NullPointerException

索引越界異常

IndexOutOfBoundsException是一個執行時期例外,當用於存取陣列或集合的索引為負數或大於或等於陣列或集合的大小時拋出。為了防止這種異常的發生,我們必須確保用於存取陣列或集合的索引在其範圍內,即它必須大於或等於零且小於陣列或集合的大小。

ArrayIndexOutOfBoundsException

ArrayIndexOutOfBoundsException是IndexOutOfBoundsException的一種類型,當嘗試存取無效索引處的陣列時會引發該例外狀況。在 Java 中,陣列索引從0開始,到length()-1結束,其中length()是數組中元素的數量。如果嘗試存取超出此範圍的索引處的元素,Java 將拋出ArrayIndexOutOfBoundsException。當遇到ArrayIndexOutOfBoundsException時,您應該檢查程式碼以確保在存取陣列中的元素時使用正確的索引。

StringIndexOutOfBoundsException

StringIndexOutOfBoundsException是一種IndexOutOfBoundsException類型,當嘗試存取字串中具有無效索引的字元時,會引發該異常。與前面的ArrayIndexOutOfBoundsException一樣,請記住,在 Java 中,字串的索引從0開始,到length()-1結束,其中length()是字串中的字元數。如果嘗試存取超出此範圍的索引處的字符,則可能會遇到StringIndexOutOfBoundsException。如果遇到StringIndexOutOfBoundsException,您應該檢查程式碼以確保在存取字串中的字元時使用正確的索引。

類別轉換異常

當我們嘗試將物件轉換為與其實際類型不相容的類型時,就會發生此異常。為了解決這樣的問題,重要的是要確保您的 Java 程式僅嘗試將物件轉換為其實例的類別。在套用強制轉換之前,您可以使用instanceof運算子檢查物件的類型。

非法參數異常

IllegalArgumentException是一種RuntimeException,當使用非法或不適當的參數呼叫方法時拋出。換句話說,當使用超出預期範圍或不具有預期格式或結構的參數呼叫方法時,可能會發生此錯誤。例如,一個方法需要一個正數作為參數,而我們提供了一個負數,這是一個無效的輸入。如果遇到IllegalArgumentException,您應該檢查您的程式碼以確保您使用有效且適當的參數呼叫方法。

非法狀態異常

IllegalStateException是一種RuntimeException,當物件處於不適合執行操作的狀態時拋出。如果對不處於預期狀態的物件呼叫方法,則可能會發生這種情況。例如,如果我們建立一個資料庫連接物件然後關閉它。然後,如果我們嘗試在關閉的連接中建立Statement對象,它將拋出IllegalStateException 因為createStatement()方法需要開啟的連接。如果遇到IllegalStateException,您應該檢查您的程式碼以確保您正在對處於適當狀態的物件呼叫方法。

不支援的操作異常

UnsupportedOperationException是一種RuntimeException類型,當嘗試對物件執行不支援的操作時會引發該例外狀況。當我們呼叫物件未實作或物件不支援的方法時,可能會發生此錯誤。為了防止拋出異常,我們不應該呼叫物件不支援的此類操作。我們需要檢查程式碼以確保我們正在呼叫支援該操作的物件上的方法。

算術異常

ArithmeticException是一種RuntimeException,當算術運算產生無效結果時拋出。當我們嘗試使用無效或無效參數執行算術運算時,可能會發生此異常。例如,當嘗試除以零時。為了解決這個問題,我們可以在執行算術運算之前進行輸入驗證並確保參數符合所需條件。

安全異常

SecurityException是RuntimeException的一種,當程式執行期間​​發生安全違規時拋出。當程式嘗試執行安全性原則不允許的操作時,可能會發生此錯誤。為了解決這個問題,我們必須確保我們能夠存取資源並執行我們擁有特定權限的操作。

數字格式異常

NumberFormatException是RuntimeException的一種類型,當呼叫方法將字串轉換為數字格式,但字串的格式不正確時,會引發該例外。為了解決這個問題,我們必須先驗證使用者的輸入,然後再嘗試轉換它。也請檢查您的程式碼,以確保您正在嘗試轉換格式適合目標數字類型的字串。

中斷異常

InterruptedException是檢查異常,如果執行緒正在等待、休眠或阻塞某個事件並且該事件被另一個執行緒中斷,則會引發該例外狀況。當執行緒正在等待輸入、釋放鎖定或完成某些其他操作,並且另一個執行緒中斷等待執行緒時,可能會發生該錯誤。要解決此問題,您可以捕獲InterruptedException並透過清理資源、停止執行緒或採取其他適當的操作來回應。如果遇到InterruptedException,您應該檢查程式碼以確保正確處理執行緒中斷。

文件未找到異常

FileNotFoundException 是一個檢查異常,當程式嘗試存取不存在或無法在指定位置找到的檔案時引發。如果檔案拼字錯誤、移動或刪除,甚至程式沒有存取該檔案所需的權限,則可能會出現此錯誤。若要修復該錯誤,您可以執行輸入驗證以確保檔案路徑正確且程式具有存取該檔案的必要權限。

IO異常

IOException是 Java 中的檢查異常,表示執行輸入或輸出操作(例如讀取或寫入檔案或網路套接字)時遇到的錯誤。發生這種情況的原因有很多種,例如指定的檔案遺失或無法存取、網路錯誤或權限不足。要解決該問題,您需要執行多項操作,例如檢查錯誤訊息、使用try-catch處理異常、關閉資源、檢查檔案權限等。

沒有這樣的方法異常

NoSuchMethodException是當我們嘗試呼叫類別中不存在的方法時在運行時引發的異常。如果我們使用Class.getMethod()Class.getDeclaredMethod()呼叫方法,並且在類別或介面中找不到指定的方法名稱,通常會發生此異常。當我們嘗試使用java.lang.reflect.Method類別呼叫方法並且指定的方法名稱在物件中不存在時,也可能會發生異常。為了避免此異常,請確保使用正確的方法簽署和存取說明符呼叫有效的方法。

沒有這樣的欄位異常

NoSuchFieldException是當我們嘗試存取不在類別中的欄位時發生的運行時異常。當我們使用Class.getField()Class.getDeclaredField()呼叫方法並且在類別或介面中找不到指定的欄位名稱時,通常會發生此異常。此外,如果我們嘗試使用java.lang.reflect.Field類別存取欄位並且指定的欄位名稱在物件中不存在,也可以呼叫它。為了避免此異常,請確保您使用正確的名稱和存取修飾符存取有效欄位。如果您要存取私有字段,請務必使用getDeclaredField()方法而不是getField()方法。

非法存取異常

IllegalAccessException是當我們嘗試存取類別中的欄位或方法但沒有必要的存取權限時發生的執行階段異常。當我們嘗試從類別外部存取私有欄位或方法時,或者當我們嘗試從不是原始類別的子類別的類別存取受保護的欄位或方法時,通常會出現此異常。當嘗試存取已被java.lang.reflect.AccessibleObject類別標記為不可用的欄位或方法時,也可以呼叫它。為了避免此問題,請確保您對嘗試存取的欄位或方法擁有必要的權限。如果欄位或方法是私有的,您可能需要使用反射並將AccessibleObject設為true(才能存取它)。但是,在使用反射存取私有欄位或方法時要小心,因為它可能會破壞封裝並損害類別的完整性。

驗證錯誤

verifyError 是執行時錯誤,是LinkageError 的子類別。當 Java 虛擬機器 (JVM) 遇到違反某些驗證規則的類別檔案時,就會發生這種情況。當編譯 Java 類別時,編譯器會檢查字節碼是否遵循某些規則和限制,例如類型安全性以及堆疊和局部變數的正確使用。如果類別檔案違反了這些規則,JVM在執行時載入和檢查該類別時將拋出VerifyError 。為了避免VerifyError,請確保您的程式碼遵循Java 語言的正確語法和語義。如果您遇到VerifyError,您應該檢查您的程式碼以確保其有效且不違反Java字節碼驗證規則。

記憶體不足錯誤

OutOfMemoryError是Error 的子類,Error 是一種Throwable類型,會引入無法在運行時解決的嚴重問題。儘管 Java 8 在垃圾收集和記憶體管理方面進行了一些改進,但如果您的應用程式使用過多記憶體或錯誤地管理記憶體使用情況,您仍然可能會遇到OutOfMemoryError 。為了避免OutOfMemoryError,您需要正確管理 Java 應用程式中的記憶體使用量。這涉及使用有效使用記憶體的資料結構和演算法,避免不必要的物件創建,以及在不再需要時正確刪除物件。此外,您可以在執行 Java 程式時 使用-Xmx標誌來增加 JVM 的最大堆大小。

堆疊溢位錯誤

StackOverflowError是當程式所需的堆疊大小超過分配給它的記憶體量時發生的一種錯誤。當程式呼叫太多巢狀方法或方法遞歸呼叫自身太多次時,可能會發生這種情況,從而導致無限循環。Java 虛擬機器 (JVM) 為執行堆疊分配固定數量的內存,用於追蹤方法呼叫和局部變數。當堆疊溢位時,JVM 會拋出StackOverflowError。為了避免StackOverflowError,確保您的 Java 程式充分利用遞歸和方法呼叫非常重要。如果遇到StackOverflowError ,您可以在執行 Java 程式時 嘗試使用-Xss標誌來增加堆疊大小。

呼叫目標異常

IncationTargetException是 Java 反射機制拋出的檢查例外。它是java.lang.reflect.InitationTargetException套件的一部分,用於指示在方法或建構子呼叫期間發生異常。當使用Java反射機制呼叫方法或建構子時,將呼叫java.lang.reflect.Methodjava.lang.reflect.Constructor類別的invoke()方法。如果呼叫的方法或建構子拋出異常,則invoke()方法會捕獲該異常並將其包裝在InvocableTargetException中。然後這個異常被傳遞給invoke()方法的呼叫者。要修復IncationTargetException,我們需要捕捉它,使用getCause()方法取得根本原因異常,並相應地處理根本原因異常。請注意,根本原因可能是檢查異常或運行時異常,因此請務必正確處理它。

修復 Java 中最常見的異常方法

如何修復空指標異常

場景:您有一個方法可以存取值為null的物件。
String title= null;
System.out.println(title.length()); // Это вызовет NullPointerException
解決方案#1:在使用前檢查物件是否為空。
if(title!= null) {
   System.out.println(title.length());
} else {
   System.out.println("title is null");
}
解決方案#2:使用Optional來避免NullPointerException
Optional<String> optionalTitle = Optional.ofNullable(getTitle());
if (optionalTitle.isPresent()) {
   String title= optionalTitle.get();
   System.out.println("Title: " + title);
} else {
   System.out.println("Title is not available.");
}

如何修復 ArrayIndexOutOfBoundsException

場景:您嘗試存取陣列的索引超出其範圍。
int[] numbers = {4, 5, 6};
System.out.println(numbers[3]);   // Это вызовет ArrayIndexOutOfBoundsException
解決方案:在存取陣列之前檢查陣列的長度,並確保使用有效的索引。
int[] numbers = {4, 5, 6};
if (numbers.length > 3) {
   System.out.println(numbers[3]);
} else {
   System.out.println("ArrayIndexOutOfBoundsException: Please use valid indexes of the Array");
}

如何修復 ClassCastException

場景:您試圖將物件轉換為與其實際類型不相容的類型。
Object obj = "Java Exception";
Integer number = (Integer) obj; // Это вызовет ClassCastException
解決方案:確保僅將物件轉換為與其相容的類型。
Object obj = "Java Exception";
if(obj instanceof Integer) {
   Integer number = (Integer) obj;
   System.out.println(number);
} else {
   System.out.println("Object cannot caste to Integer");
}

如何修復 IllegalArgumentException

場景:您向方法傳遞了無效參數。
public void printNumber(int number) {
   if(number <= 0) {
      throw new IllegalArgumentException("You cannot pass a negative number or zero");
   }
   System.out.println(number);
}

printNumber(-1); // Это вызовет IllegalArgumentException
解決方案:確保將有效的參數傳遞給方法。在這種情況下,請傳遞一個正數。
printNumber(1); //  Это успешно напечатает 1.

如何修復 IllegalStateException

場景:物件處於無效狀態。
public class Bike {

   private Boolean isStarted;

   public void start() {
      if(isStarted) {
        throw new IllegalStateException("Bike is already started");
      }
      isStarted = true;
      System.out.println("Bike started");
   }
}

Bike bike= new Bike();
bike.start();
bike.start(); // Это вызовет IllegalStateException потому что bike is already started
解決方案:確保正確維護物件狀態。
Bike bike= new Bike();
bike.start();

如何修復 UnsupportedOperationException

場景:您使用物件不支援的操作。一個流行的範例是,當您對不可變集合使用remove()操作時,您可能會看到UnsupportedOperationException異常。
List<String> list = Arrays.asList("Java", "Angular", "Spring");
list.add("Python"); // Это вызовет UnsupportedOperationException
由於Arrays.asList()方法傳回一個不可變列表,因此它不支援新增或刪除元素。 解決方案:確保僅對物件呼叫支援的操作。
List<String> list = new ArrayList<>(Arrays.asList("Java", "Angular" "Spring"));
list.add("Python");
System.out.println(list);

如何修復算術異常

場景#1:您正在嘗試執行產生小數結果的整數除法運算。
int i = 10;
int j = 4;
int k = i/j; // Это вызовет исключение ArithmeticException: целочисленное деление будет дробным
這裡除法運算的結果是 2.5,它是一個小數值。因為整數不能儲存小數值,所以會拋出ArithmeticException解決方案:為了避免這種異常,我們可以使用支援小數值的資料類型(例如double)來儲存除法運算的結果。這是一個例子:
int i = 10;
int j = 4;
double k = (double) i/j;
場景#2:您嘗試除以零,但出現此異常。這是最常見的情況。
int i = 4;
int j = 0;
int k = i/j; // Это вызовет исключение ArithmeticException: нельзя делить на ноль
解:正確處理除零。例如,下面的程式碼演示了正確的處理。
int i = 4;
int j = 0;
if(j != 0) {
int k = i/j;
System.out.println(k);
} else {
System.out.println("ArithmeticException: Cannot divide by zero");
}

如何修復 IndexOutOfBoundsException

場景:您正在嘗試存取索引位於集合之外的集合。
List<String> list = Arrays.asList("Apple", "Papaya", "Mango");
System.out.println(list.get(3)); // Это вызовет IndexOutOfBoundsException
解決方案:在存取集合之前檢查集合的大小,並確保使用有效的索引。
List<String> list = Arrays.asList("Apple", "Papaya", "Mango");
if (list.size() > 3) {
   System.out.println(list.get(3));
} else {
   System.out.println("You are using the Index which is out of bounds");
}

如何修復 IOException

場景:由於文件不可訪問,輸入/輸出操作失敗。
try {
   File inputFile = new FileReader("pqr.txt");
   BufferedReader reader = new BufferedReader(inputFile);
   String line = reader.readLine();
   System.out.println(line);
} catch (IOException e) {
   e.printStackTrace();
}
解決方案:處理I/O錯誤並確保資源正確關閉。
File inputFile = new File("pqr.txt");

if (!inputFile.exists() || !inputFile.canRead()) {
 System.out.println("The input file is missing or not readable.");
 return;
}

try {
BufferedReader reader = new BufferedReader(inputFile);
 String line = reader.readLine();
 System.out.println(line);
  reader.close();
} catch (IOException e) {
 e.printStackTrace();
}
請注意,作為替代方案,我們可以使用Java 7 中引入的try-with-resource功能來自動關閉資源,如下所示。我們可以在try語句中宣告一個或多個資源,Java 會在區塊結束時自動關閉這些資源,無論區塊是否正常完成或拋出例外。
try (BufferedReader reader = new BufferedReader(new FileReader("pqr.txt"))) {
....
} catch {
....
}

如何修復 FileNotFoundException

場景:在指定位置未找到該檔案。
try {
     BufferedReader reader = new BufferedReader(new FileReader("abc.txt"));
     String line = reader.readLine();
     System.out.println(line);
     reader.close();
} catch (FileNotFoundException | IOException e) {
     System.out.println("An error has occurred while reading the file: " + e.getMessage());
}
解決方案:確保該文件存在並且您具有存取該文件的適當權限。
try {
    File file = new File("abc.txt");
    if(!file.exists()) {
    throw new FileNotFoundException("File not found at the specified location");
    }
    BufferedReader reader = new BufferedReader(new FileReader(file));
    String line = reader.readLine();
    System.out.println(line);
    reader.close();
} catch (IOException e) {
    e.printStackTrace();
}

如何修復 NoSuchMethodException

場景:如果您嘗試存取無法找到的方法。
public class TestClass {
   public void sayHello() {
      System.out.println("Hello");
   }
}

TestClass obj = new TestClass();
Method method = obj.getClass().getMethod("printHello"); // Это вызовет NoSuchMethodException
解決方案:驗證方法是否存在,且方法名稱和簽章是否正確。
public class TestClass {
   public void sayHello() {
      System.out.println("Hello");
   }
}

TestClass  obj = new TestClass();
try {
    Method method = obj.getClass().getMethod("sayHello");
} catch (NoSuchMethodException e) {
    e.printStackTrace();
}

如何修復並發修改異常

場景:集合在迭代時會改變。
List<String> list = new ArrayList<>();
list.add("Java");
list.add("Python");
for (String str : list) {
  list.remove(str);  // Это вызовет ConcurrentModificationException
}
解決方案:使用迭代器迭代集合併使用迭代器方法修改它。
List<String> list = new ArrayList<>();
list.add("Java");
list.add("Python");
Iterator<String> iterator = list.iterator();
while (iterator.hasNext()) {
    String str = iterator.next();
    iterator.remove();
}
留言
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION