Skip to main content

Dart 錯誤處理

錯誤處理

Dart 提供了兩個主要的異常類型:

  1. Exception:表示程序中的邏輯錯誤或其他可預期的問題。開發者可以使用這個類型來表示可以處理或恢復的錯誤。
  2. Error:表示程序中的嚴重問題,通常是程序無法恢復的錯誤,如內存溢出、無效的狀態等。 或是開發者也可以自定義異常來更靈活處理錯誤。
info

錯誤處理在各種程式語言都很重要!

  1. 管理錯誤狀態:通過捕獲異常,開發者可以根據具體情況做出相應的處理,如提示用戶、重試操作、記錄日誌等。
  2. 避免程式碼中斷執行:通過適當的異常處理,可以防止程序因未處理的異常而崩潰,從而提高程序的健壯性和穩定性。

Catch 捕獲異常

Dart 捕獲異常是使用 try 配合 oncatch

try {
breedMoreLlamas();
} on OutOfLlamasException {
buyMoreLlamas();
}

也可以使用多個 catch 來處理不同類型的異常:

try {
breedMoreLlamas();
} on OutOfLlamasException {
// 處理特定的 OutOfLlamasException 異常
buyMoreLlamas();
} on Exception catch (e) {
// 處理所有其他的 Exception 類型的異常
print('Unknown exception: $e');
} catch (e) {
// 處理所有其他未被捕獲的異常
print('Something really unknown: $e');
}
info

oncatch 的差異

  • on:用於處理特定類型的異常。適合需要區分不同異常類型並進行相應處理的情況。
  • catch:用於捕獲所有異常,並可以獲取異常對象和堆棧跟蹤 (Stack Trace)。適合處理通用異常和需要詳細異常信息的情況。 從概念尚可以知道 oncatch 負責的事情類似但本質不一樣:
  • on 就像售票員檢查入場券一樣,只讓有有效入場券的人進入。這意味著當特定類型的異常發生時,相應的處理程序將被觸發。
  • catch 就像救護人員在事故現場一樣。無論異常的類型是什麼,catch 都會將它捕獲並進行相應的處理,無需對異常進行額外的分類。

Throw 拋出異常

以下是拋出異常的範例:

// example1
throw FormatException('Expected at least 1 section');

// example2
throw 'Out of llamas!';

// example3
void distanceTo(Point other) => throw UnimplementedError();

也可以透過 rethrow 在異常處理過程中重新抛出異常,以便讓上層調用者能夠感知和處理這個異常:

void misbehave() {
try {
dynamic foo = true;
print(foo++); // Runtime error
} catch (e) {
print('misbehave() partially handled ${e.runtimeType}.');
rethrow; // Allow callers to see the exception.
}
}

void main() {
try {
misbehave();
} catch (e) {
print('main() finished handling ${e.runtimeType}.');
}
}

解釋一下上面 rethrow 做了什麼:

  1. misbehave() 函式開始執行。
  2. misbehave() 函式中,嘗試對一個 bool 變數進行自增操作,這是不合法的。
  3. 由於自增操作不合法,導致運行時錯誤。
  4. 運行時錯誤被 catch 塊捕獲,程式執行進入 catch 塊。
  5. catch 塊中,打印一條消息,表明 misbehave() 函式部分處理了這個異常。
  6. catch 塊中,使用 rethrow 關鍵字重新抛出這個異常。
  7. 異常被重新抛出後,它會繼續向上傳播到 main() 函式。
  8. 異常被 main() 函式中的 catch 塊捕獲。
  9. main() 函式的 catch 塊中,打印一條消息,表明 main() 函式處理了這個異常。

Finally

finally 用於確保某些程式碼無論異常是否被拋出都會執行。
這意味著即使在 try 區塊中的程式碼引發異常,finally 中的程式碼仍然會被執行。
如果沒有 catch 子句去捕獲異常,則 finally 執行完畢後,該異常會繼續向外傳遞。

try {
breedMoreLlamas();
} finally {
// Always clean up, even if an exception is thrown.
cleanLlamaStalls();
}