Dartにおける例外の宇宙:シンプルなガイド

Mabelさんが2023年12月7日に投稿

Dartでの開発はチャレンジに満ちたワクワクする旅ですが、その重要な側面の一つが例外処理です。この記事では、例外処理について分かりやすく解説して、エンドユーザーにもアクセスしやすくしていきます。

例外処理を実装する重要性は、常に予測できない状況に対処できるようにするためであり、ユーザーに影響がないようにするためです。そうすることで、私たちは予期せぬ状況を効果的に扱える堅牢なアプリケーションを構築することができます。

成功のみのプログラミング

プログラミングの世界では、全てが常にうまくいくというパスだけにフォーカスしたソリューションをプログラムするという一般的なアプローチがあります。しかし、成功だけを考えていると、現実の状況、物事が期待通りに機能しないという状況を扱うためにアプリケーションを準備することができません。これらの問題を無視することで、予測不可能で低品質のアプリケーションになってしまいます。

成功の物語を越えて考え、システムを特別で例外的な状況に備えることが重要です。

エラーと例外の違いを理解しましょう

Dartのドキュメントにはエラーハンドリングについてより詳しい情報がありますが、目的を持って簡潔に説明するために、ここでは簡単な定義をカバーします:

例外

プログラムが対処を予期し、準備するべき状況。

エラー

発生すべきでなく、開発者が避けるべきだった状況。

Try-On-Catch-Finally: 予期せぬ状況に対処する

では、どのようにして予期せぬ状況に対処するのでしょうか?Dartを含む多くのプログラミング言語には、これを助けてくれるコード構造があります。それがTry-On-Catch-Finallyです。

Try

Tryは、失敗を引き起こす可能性のあるコードブロックを持っているときに使用されます。この構造を使ってコードをラップすることで、適切に処理できるようにします。

以下の例では、toInt()メソッドがハッピーパスのみを想定して構造化されていますが、エラーが発生した場合、システムは単に「クラッシュ」します。

void main() => print(toInt("5"));

int toInt(String value) {
   return int.parse(value); //Works perfectly
}

この状況をシステムが処理する方法は何でしょうか?

Try構造を使用してみましょう。

void main() {
   try {
     print(toInt("not a number"));
   } // この後に 'catch', 'on', 'finally' で完結させる必要があります
}

int toInt(String value) {
   return int.parse(value);
}

On

意図的に例外を引き起こし、ユーザーに影響を与えずにそれを処理するプロセスを開始したので、投げられる例外を正確に知っている場合にどのように扱うかを理解しましょう。

例えば、"not a number"という文字列を渡すと、toInt()メソッドはFormatExceptionを投げることがわかっています。この例外をキャッチするためには、on構造を使用します。

void main() {
   try {
     print(toInt("not a number"));
   } on FormatException {
     print("The value is not a valid number.");
   }
}

Catch

catchの使用は、別の方法で例外をキャプチャすることです。

例外をキャッチするということは、それがさらに伝播されないことを意味します。ユーザーが何が悪かったのかを理解できるように、それに対処する機会です。

void main() {
   try {
     print(toInt("not a number"));
   } on FormatException catch (e) {
     print(e.toString());
   }
}

Finally

finallyは、例外が投げられるかどうかに関わらず、特定のコードの断片が実行されることを保証する節です。例外が投げられた場合、それはその後にトリガーされます。

void main() {
  try {
    print(toInt("not a number")); // 1º
  } on FormatException catch (e) {
    print(e.toString()); // 2º
  } finally {
    print("we reached the end"); // 3º
  }
}

Throwを使用した例外のスロー

非常に一般的な状況は、操作の成功または失敗をブーリアンで示したり、何らかの値を返して成功またはエラーを表すことです。しかしこのような場合に、エラーの正確な原因を見つけることは、干し草の中の針を探すようなものになります。

以下では、toInt()メソッドが何か特別なことが起こったときに情報を与えてくれないことがわかります。

例えば、私は渡された文字列は空であってはならないというルールを作りました。しかし、toInt()メソッドが0を返す場合、ただそれを確認する方法しかありません。

私が例えばtoInt("0")を通知すると、問題になります。成功の0なのか、エラーの0なのかをどうやって知ることができるでしょう?

void main() {
    print(toInt("0")); // return 0 - success
    print(toInt("")); // return 0 - error
}

int toInt(String value) {
   if (value.isEmpty) return 0; // <- indicates an error

   return int.parse(value); // <- indicates success
}

このプロセスを簡単にするために、throwで例外を投げるという概念を理解しましょう。この慣習は私たちのコードの明確さを向上させるのに役立ち、問題を理解し解決するための明確な道筋を提供しますが、抽象的な値の不確実性はありません。

void main() {
   try {
     print(toInt(""));
   } on Exception catch (e) {
     print(e.toString());
   }
}

int toInt(String value) {
   if (value.isEmpty) {
     throw Exception("The provided value is empty.");
   }

   return int.parse(value);
}

カスタム例外の作成

私たちのコード、そして日常のプロジェクトの明確さをさらに向上させるために、カスタマイズされた例外を作成することができます。

私はそれぞれのルールに対して例外を作成します:

  • 渡された値は空であってはならない;
  • 渡された値は負であってはならない。
class InformedValueIsEmptyException implements Exception {
   
   String toString() => 'The provided value is empty.';
}

class InformedValueIsUnderLimitException implements Exception {
   String value;

   InformedValueIsUnderLimitException({required this.value});

   
   String toString() => "The provided value can't be less than 0. You entered '$value'.";
}

例外のプロパティ

時々、例外として、ユーザーに問題をよりよく理解するために役立つかもしれない情報を提供する必要があります。たとえば、以下の例外では、ユーザーに提供された値xが私たちのルール - この値が負であってはならない - を満たしていないことを明確にします。

💡 必要なパラメータを特定するには、ユーザーに情報をどのように明確に伝えるかを考えてください。

class InformedValueIsUnderLimitException implements Exception {
  String value;

  InformedValueIsUnderLimitException({required this.value});

  
  String toString() => "The provided value can't be less than 0. You entered '$value'.";
}

メモリ保存

この記事では、Dartにおける例外処理の世界を探求しました。例外処理を実装する方法を理解することで、私たちのアプリケーションを強化し、予期せぬ状況を効果的に処理する準備を整えることができます。

プログラミングでは、全てが完璧に機能することにだけ焦点を当てることが多いです。現実世界での状況に備えることを怠らないようにすることが大切です。成功例を超えて考え、システムが例外的な状況に対処するための最善のアプローチを行うことが求められます。

DartのTry-On-Catch-Finally構造は予期せぬ状況に対処するための強力なツールです。tryを使用して失敗する可能性のあるコードブロックをラップし、onで特定の例外をキャッチし、catchで例外を処理し、finallyで例外が発生した後でもコードの実行を保証します。

throwを使用して例外を投げる方法について学び、ブーリアンや特殊な値を使って成功または失敗を示すという一般的な慣行を捨てました。また、InformedValueIsEmptyExceptionInformedValueIsUnderLimitExceptionのようなカスタム例外を作成しました。それにより、私たちが出くわした問題についての明確さを提供し、コードを理解して保守することを容易にしました。

要するに、良好な例外処理慣行を採用し、カスタム例外を作成することで、コードの品質を高め、より堅牢でセキュアかつ理解しやすいアプリケーションを促進します。

💡 この記事は、私のAluraコースDart: 例外処理とNull Safetyに対処するに関する学習メモに基づいて制作されました。

こちらの記事はdev.toの良い記事を日本人向けに翻訳しています。
https://dev.to/eusoumabel/the-universe-of-exceptions-in-dart-an-uncomplicated-guide-1dko