Dartには例外処理の機能が備わっています。
例外を受け取る
発生した例外を受け取るには、try - catch を使います。
サンプルコード
void main() {
int a = 0;
try {
a.length;
} catch (final NoSuchMethodException e) {
print(e);
}
}
このコードではint型の変数のlengthプロパティを参照していますが、そのようなプロパティ(getterメソッド)はint型には存在しないので
NoSuchMethodException が発生します。これを catch で受け取っています。
catch に型を指定しないこともでき、そうすることであらゆる型のオブジェクトを受け取ることができます。また、1つの try に対して複数の catch を書くこともできます。その場合は、上から順に見て行って最初に型が一致したものが実行されます。
void main() {
int a = 0;
try {
a.length;
} catch (final var e) {
/* ここが実行されます。 */
}
try {
a.length;
} catch (final NoSuchMethodException e) {
/* ここが実行されます。 */
} catch (final e) {
/* ここは実行されません。 */
}
}
例外発生箇所のスタックトレースを受け取るには、catch の2つめの要素として指定します。
void main() {
int a = 0;
try {
a.length;
} catch (final NoSuchMethodException e, var stack) {
print("exception: $e");
print("stack: $stack");
/*
exception: NoSuchMethodException : method not found: 'get:length'
Receiver: 0
Arguments: []
stack: 0. Function: 'Object.noSuchMethod' url: 'bootstrap' line:2698 col:3
1. Function: '::main' url: 'file:///home/dart-ing/dart/ExceptionTest/ExceptionTest.dart' line:4 col:13
*/
}
}
このように例外を簡単に受け取ることができますが、実際には例外の発生を予期するのは難しいことです。コードの中で受け取られなかった例外は、実行環境側へ渡されて Unhandled exception としてそれぞれの方法で処理されます。
後処理を実装する
try を抜けた時に必ず実行されるコードを finally に書くことができます。
サンプルコード
void main() {
int a = 0;
try {
a.length;
} catch (final NoSuchMethodException e) {
print(e);
}
finally {
print("finally");
}
}
この場合、catch による例外処理が行われてから、最後に finally が実行されます。
例外を発生させる
例外を発生させるには throw を使います。
サンプルコード
void main() {
try {
throw new Exception("message");
} catch (final Exception e) {
print(e); // Exception: message
}
}
標準APIでの例外
Dartの標準API(
dart:coreなど)にはあらかじめいくつかの例外が用意されています。それらはすべて
Exception から派生した型になっています。例外についてはいろいろな考え方がありますが、自分で例外を用意する場合には Exception から派生した型を使ったほうがわかりやすいでしょう。
非同期処理でも例外を処理する必要があります。例えばファイルI/Oなどです。Dartでは
File の非同期処理を
Future を使って実装しているため、ファイルI/Oの例外処理をするならば Future の例外処理について知る必要があります。といっても特に難しいものではなく、例外が発生すると
Future.handleException に指定した関数が呼ばれますので、そこで処理することになります。Future については以前の記事(
Dartで未来(Future)の処理を実装する)も参考にしてください。