跳至主要内容

[Dart] 錯誤處理

錯誤處理​

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

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

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

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

Catch 捕獲異常​

Dart 捕獲異常是使用 try 配合 on 跟 catch:

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');
}
資訊

on 跟 catch 的差異

  • on:用於處理特定類型的異常。適合需要區分不同異常類型並進行相應處理的情況。
  • catch:用於捕獲所有異常,並可以獲取異常對象和堆棧跟蹤 (Stack Trace)。適合處理通用異常和需要詳細異常信息的情況。 從概念尚可以知道 on 跟 catch 負責的事情類似但本質不一樣:
  • 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();
}