Dartの例外処理と裏ワザ（？）

# 例外の発生
例外を投げるには`throw`構文を用います。最も単純な形は以下のように`Error`オブジェクトを投げるコードです。

```dart
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`を使います。

```dart
  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...と、とても多いので、[こちら](https://api.dartlang.org/apidocs/channels/stable/dartdoc-viewer/dart-core.Error)のAPIドキュメントを見つつお好みの例外を探し当ててください。  
もしくは、自分でErrorクラスを継承してオリジナルのErrorを作ってもいいと思います。

```dart
class DoorLockedError extends StateError {
  DoorLockedError() : super("door is locked");
}
```

# 例外を処理する
例外の処理にはいろんな言語でお馴染みの`try`、`catch`、`finally`を使います。

## 例外のメッセージだけ欲しい場合
もっとも単純な形はこちら。

```dart
void main() {
  var lockedDoor = new Door(true);
  try {
    lockedDoor.openDoor();
  } catch(e) {
    print(e); //Bad state: the door is locked
  }
}
```

## メッセージとスタックトレースが欲しい場合
一緒にスタックトレースも欲しい場合は次のように書きます。

```dart
void main() {
  var lockedDoor = new Door(true);
  try {
    lockedDoor.openDoor();
  } catch(e, stackTrace) {
    print(e); //Bad state: the door is locked
    print(stackTrace); //スタックトレース
  }
}
```

## 例外の種類ごとに処理を変えたい場合
発生した例外の種類ごとに特別な処理がしたい場合は以下の`on`構文を用います。

```dart
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`部分を省くことが出来ます。

```dart
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`文で必ず実行させたい終了処理を書くことが出来ます。

```dart
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)`で出力されたものですから、つまり

```dart
print(e.toString());
```

となっているわけです。  

何が言いたいかというと、catch文は実は

```
catch(Object e){
```

なのです。 **『nullでない全てのオブジェクトがthrowできる』** という機能の結果として、catch文に入ってくる例外はObject型になっています。すなわち、以下のコードが正常に動作します。

```dart
void throwError() {
  throw new DateTime.now();
}

void main() {
  try {
    throwError();
  } catch(e) {
    print(e); //2014-07-15 19:48:02.032
  }
}
```

あらゆるオブジェクトをthrowできるというのは面白い機能だと思います。使いどころは余り思いつきませんが覚えておくといつか役に立つかもしれません。