iT邦幫忙

第 12 屆 iThome 鐵人賽

DAY 13
0

例外 (Exception)

什麼是例外?例外就是不正常。在程式語言的範疇中,例外就是當有一個事件發生,而且會中斷正常流程。例如,當我們需要取得字串的長度,結果傳進來的字串是空值 (Null),空值表示在記憶體中還沒有設定內容,由不存在的內容取得字串長度是不合法的,故此時會發生例外。

在 Dart 中,如果發生例外卻沒有去處理,那麼就會暫停 Isolate ,且程式被中斷。

Dart 的例外是「未經處理的例外 (Unchecked exception)」:Dart 不會強迫處理每一個會拋出異常函數。與之對立的是 Java:在當呼叫的函數會拋出例外,那麼使用該函數的類或是其子類別,一定要將例外捕捉,

雖然 Dart 不會強迫處理例外,可以讓程式碼乾淨許多,但是函數若發生例外時,程式還是會中斷。

如何處理例外事件?

利用 try/catch 來捕捉例外事件。

try-catch

try-catch 的使用方式如下:將有可能發生例外的程式碼置於 try{ } 裡,當程式碼發生例外時,若與 catch 內預期捕捉到的例外相同,則會執行 catch 裡面的程式碼。其中 catch 裡面的 (error) 為該例外的識別碼 (Identifier),我們可以利用 error 得知詳細的例外訊息。

try{
	//Function which may throw an exception
}catch(error){
	//Error handle
}

範例:有一個 List 裡面有三個元素,當使用 for 迴圈取值時,將錯誤的索引值帶入此 list 中,那麼就會噴出例外的訊息,程式也因此中斷。

var list = [1,2,3];  
for(var i=0; i<=l.length; i++){
   print(list[i]);
}

//Unhandled exception:
//RangeError (index): Invalid value: Not in inclusive range 0..2: 3

  • 利用 try-catch 將 for 迴圈包起來
var list = [1,2,3];
try{
	for(var i=0; i<=l.length; i++){
	   print(list[i]);
	}
}catch(error){
	print(error);
}

//RangeError (index): Invalid value: Not in inclusive range 0..2: 3

→ 程式不會因為例外而中斷。


在 Dart 中,有眾多預設的例外 (Exception) 以及錯誤 (Error)。

我們可以使用 on Exception_Name catch (identifier) 或是 on Error_Name catch (identifier)來捕捉特定的例外或錯誤。

var list = [1,2,3];
try{
	for(var i=0; i<=l.length; i++){
	   print(list[i]);
	}
}on RangeError catch(error){
	print(error);
}

Throw

例用關鍵字 throw 我們也可以自行拋出例外、錯誤訊息。

範例:有一個函數還沒有實作內容,我們可以拋出 UnimplementedError,當呼叫此函數就會拋出錯誤。

void save(String content) => throw UnimplementedError();

void main(){
	save('content');
}

//UnimplementedError

除了可以拋出 Dart 預設的例外、錯誤,我們也可以自行實作例外、錯誤。

範例:

class MyError extends Error{
  final String message;

  MyError(this.message);

  @override
  String toString() {
    return 'MyError: $message';
  }
}

測試:

void main(){
	throw MyError('This is my customized error');
}

//Unhandled exception:
//MyError: 'This is my customized error'

Finally

使用 try-catch 捕捉例外、錯誤,當例外、錯誤發生時,原本的流程就會被中斷,接者會移動到 catch 中。如果有些事情一定需要處理,不管是正常的流程結束,或是錯誤的流程結束。

例如:有一個發送 log 的系統,當正常時,會把所有收集到的 log 發送出去,若有錯誤發生,則發送錯誤的訊息。

關鍵字 finally 可以接在 try-catch 的最後方,無論程序是否正常或是異常,在 finally 裡面的程式碼一定會被呼叫。

範例:

String log;
try{
	log = collectLog();
}catch(error){
	log = error;
}finally{
	send(log);
}

try-catch-finally 不一定需要三個都使用,我們可以只用其中兩個:try-catch 或是 try-finally,這完全取決於使用情境。

小結

例外處理是每一個程式語言都必須面對的,正向的程式邏輯編寫完成之後,反向的例外處理也必須要考慮。但是因為發生例外之後,原本的程式流程就會跳到別的地方,在處理的時候就要特別的小心。

為什麼 Dart 是未經檢查的例外,原因在於,它不希望我們用了一大堆 try-catch 去捕捉錯誤,只要針對一定要捕捉的去捕捉,因為以前在開發 Java 時,很常遇到某個函數會拋出例外,我們用 try-catch 去捕捉例外,但是在 catch 裡面卻又沒有做任何事情,那麼原本應該發生錯誤通知使用者的,變成沒通知,然後可能帶者錯誤的狀態繼續往下。所以為什麼 Kotlin、Dart 都改成未經檢查的例外。


上一篇
Day 12:控制流程語句 (Control flow statements)
下一篇
Day14:類別與建構式
系列文
Dart 語言 - 開啟 Flutter 的鑰匙30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言