前のページ

言語編

次のページ


例外 (Exceptions)

Dartコードは例外をスローし捕捉(キャッチ)できる。例外とは予想されていない何かが生じたことを示すエラーである。その例外が捕捉されていないと、その例外を生起したアイソレートが保留となり、一般的にはそのアイソレートとそのプログラムは終了する。

Javaに比べて、総てのDartの例外はチェックされていない例外(unchecked exceptions)である。メソッドたちはどの例外をそれがスローするかもしれないということを宣言しておらず、また皆さんは何らかの例外を捕捉することを求められていない。

DartにはExceptionErrorの型があり、また数多くのあらかじめ定義されたそれらの副型がある。無論自分自身の例外を定義することも可能である。しかしながら、Dartのプログラムは非nullオブジェクト(単にExceptionErrorのオブジェクトでなく)を例外としてスローし得る。ErrorExceptionに関しては、基本的にErrorとそのサブクラスはプログラム・エラーであり、そのプログラムは修正が必要である。一方非エラーのExceptionは実行時エラーである。これは通常プログラムであらかじめスローされるのを防止出来ない。下表のようにAPIErrorExceptionをたどって行けば、これを実装した副型にはどんなものが存在するのか判る:

例外

内容

実装クラス

Exception

実行時エラー

Error

プログラムに問題があった場合

発生した例外は下図のようにcatchされるまで呼び出した側に伝搬してゆく。main()のなかで最終的に捕捉されたもの、またはそこでも捕捉されないエラーと例外(uncaughtまたはunhandlederrorまたはexceptionと呼ばれる)ではその時点でプログラムの進行が終了する。


finally句は例外が発生したかどうかにかかわらず実行される。catch句で捕捉されなかった例外またはエラーはfinally句が実行された後で伝搬する。



スロー (Throw)

以下は例外のスローまたは生起の例である:

throw FormatException('Expected at least 1 section');

任意のオブジェクトをスローさせることもできる

throw 'Out of llamas!';

注:運用品質のコードは通常ErrorまたはExceptionを実装した型たちをスローする。

例外をスローさせるのは一つの式であるので、式が許されるどの場所でも例外をスロー出来るし、また=>文の中でスローさせることも可能である:

void distanceTo(Point other) => throw UnimplementedError();



キャッチ(Catch)

キャッチまたは捕捉によってその例外が伝搬するのを止める(その例外を再スロー(rethrow)しない限り)。例外を捕捉するとそれの処理が可能になる:

try {
  breedMoreLlamas();
} on OutOfLlamasException {
  buyMoreLlamas();
}

ひとつ以上の型の例外をスローし得るコードを扱うときは、複数のcatch句を指定できる。スローされたオブジェクトの型に合った最初のchatch句がその例外を取り扱う。catch句が型を指定していないときは、その句がスローされたどの型のオブジェクトも処理をする:

try {
  breedMoreLlamas();
} on OutOfLlamasException {
  // 特定の例外
  buyMoreLlamas();
} on Exception catch (e) {
  // それ以外の例外
  print('Unknown exception: $e');
} catch (e) {
  // 型指定していないので総ての例外を扱う
  print('Something really unknown: $e');
}

この例(LlamaAndroidのアプリ)で示してあるように、onまたはcatchまたはその双方が使用できる。例外の型を指定する必要があるときはonを使用する。自分の例外ハンドラが例外のオブジェクトが必要な時はcatchを使う。

catch()にひとつまたは2つのパラメタを指定できる。最初はスローされた例外であり、2番目はスタック・トレース(StackTraceオブジェクト)である。

try {
  // ···
} on Exception catch (e) {
  print('Exception details:\n $e');
} catch (e, s) {
  print('Exception details:\n $e');
  print('Stack trace:\n $s');
}

それの伝搬を許すものの部分的にある例外を処理するにはrethrowキーワードを使う。

void misbehave() {
  try {
    dynamic foo = true;
    print(foo++); // ランタイム・エラーが起きる
  } catch (e) {
    print('misbehave() partially handled ${e.runtimeType}.');
    rethrow; // 呼び出した側でこの例外が見れるようにする
  }
}
void main() {
  try {
    misbehave();
  } catch (e) {
    print('main() finished handling ${e.runtimeType}.');
  }
}

DartPadで実行して確認されたい。



Finally

ある例外がスローされているか否かに関わらずそのコードが走るようにしたいときはfinally句を使う。その例外にマッチするcatch句がない場合、その例外はそのfinally句のあとに伝搬する:

try {
  breedMoreLlamas();
} finally {
  // 例外がスローされていてもclean upする
  cleanLlamaStalls();
}

finally句はマッチしているcatch句の後で走る:

try {
  breedMoreLlamas();
} catch (e) {
  print('Error: $e'); // 例外を最初に処理する
} finally {
  cleanLlamaStalls(); // その後clean up.
}



rethrowとスタックトレース

現在の例外(current exception)はスローされた最新の未処理の例外である。現在のスタック・トレース(current stack trace)は現在の例外がスローされた場所で実効が未だ終了していない現在のアイソレート内での総ての関数活性化の記録である。そのような関数活性化の各々に対し、現在のスタック・トレースには、その関数の名前、その総ての仮パラメタたちのバインディングたち、ローカル変数たちとthis、及びその関数が実行していた位置(position)が含まれる。

rethrow文は同じ例外を再スローして、その上のtryブロックに伝搬させるものである。もしrethrow文がon-catch句内に含められていないときはコンパイル時エラーである。以下はrethrowを使ってその例外を一つ上のレベルに伝搬させた例である:

errorCode() {
  try {
    var x = 5 ~/ 0;
  } catch (e, st) {
    print('Caught an exception in the errorCode() method :\n$st');
    rethrow;
  }
}
main() {
  try {
    errorCode();
  } catch (e, st) {
    // catch any error and exception
    print('Caught an exception in the main() method :\n$st');
  }
}

このコードをDartPadで実行して確認されたい。

throwは自分で作った例外をスローできる。これはプログラム開発段階で活用できる:

スタック・トレースは例えば次のように使う:

main() {
  try {
    throw "Stack trace example";
  } catch (e, s) {
    print("Caught: $e\nStack: $s");
  }
}
/*
Caught: Stack trace example
Stack: ........
*/

このコードをDartPadで実行して確認されたい。





前のページ

次のページ