例外の発生
例外を投げるにはthrow
構文を用います。最も単純な形は以下のようにError
オブジェクトを投げるコードです。
class Door {
bool locked;
Door(this.locked);
void openDoor() {
if (locked) {
throw new Error();
}
}
}
void main() {
var lockedDoor = new Door(true);
lockedDoor.openDoor();
}
これを実行すると以下のようにエラーが出ます。
Unhandled exception:
Instance of 'Error'
『インスタンスの状態が原因である』エラーを投げるにはStateError
を使います。
void openDoor() {
if (locked) {
throw new StateError("the door is locked");
}
}
Unhandled exception:
Bad state: the door is locked
Error
を継承している組み込みの例外用クラスは他にもAbstractClassInstantiationError, ArgumentError, AssertionError, CastError, ConcurrentModificationError, CyclicInitializationError, etc...と、とても多いので、こちらのAPIドキュメントを見つつお好みの例外を探し当ててください。
もしくは、自分でErrorクラスを継承してオリジナルのErrorを作ってもいいと思います。
class DoorLockedError extends StateError {
DoorLockedError() : super("door is locked");
}
例外を処理する
例外の処理にはいろんな言語でお馴染みのtry
、catch
、finally
を使います。
例外のメッセージだけ欲しい場合
もっとも単純な形はこちら。
void main() {
var lockedDoor = new Door(true);
try {
lockedDoor.openDoor();
} catch(e) {
print(e); //Bad state: the door is locked
}
}
メッセージとスタックトレースが欲しい場合
一緒にスタックトレースも欲しい場合は次のように書きます。
void main() {
var lockedDoor = new Door(true);
try {
lockedDoor.openDoor();
} catch(e, stackTrace) {
print(e); //Bad state: the door is locked
print(stackTrace); //スタックトレース
}
}
例外の種類ごとに処理を変えたい場合
発生した例外の種類ごとに特別な処理がしたい場合は以下のon
構文を用います。
void main() {
var lockedDoor = new Door(true);
try {
lockedDoor.openDoor();
} on StateError catch(e) {
print(e);
} on NoSuchMethodError catch(e) {
print(e);
} catch(e) {
print(e);
}
}
例外が発生したということだけ知りたい場合
例外の型を指定したとき、例外情報が必要ない場合はcatch
部分を省くことが出来ます。
void main() {
var lockedDoor = new Door(true);
try {
lockedDoor.of();
} on StateError{
print("StateError");
} on NoSuchMethodError{
print("NoSuchMethodError");
} catch(e) {
print(e);
}
}
上のコードはWebStormで書くと赤線表示されますが正常に動作します。どうもDartプラグインがon
構文周りにあまり対応してないようで補完も効かないです。今後に期待です
finally文
当然finally
文で必ず実行させたい終了処理を書くことが出来ます。
void main() {
var lockedDoor = new Door(true);
try {
lockedDoor.openDoor();
} catch(e) {
print(e);
} finally{
print("finish");
}
}
裏ワザ(?)
ところでなぜDartのcatch文は
catch(Error e){
ではなく
catch(e){
なのでしょうか?一番最初に挙げたErrorクラスのオブジェクトを投げて例外を発生させるコードの実行結果をよく見ると、
Unhandled exception:
Instance of 'Error'
と書かれていますね。そして、StateErrorクラスだと
Unhandled exception:
Bad state: the door is locked
です。2行目のメッセージはprint(e)
で出力されたものですから、つまり
print(e.toString());
となっているわけです。
何が言いたいかというと、catch文は実は
catch(Object e){
なのです。 『nullでない全てのオブジェクトがthrowできる』 という機能の結果として、catch文に入ってくる例外はObject型になっています。すなわち、以下のコードが正常に動作します。
void throwError() {
throw new DateTime.now();
}
void main() {
try {
throwError();
} catch(e) {
print(e); //2014-07-15 19:48:02.032
}
}
あらゆるオブジェクトをthrowできるというのは面白い機能だと思います。使いどころは余り思いつきませんが覚えておくといつか役に立つかもしれません。