1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

【Dart】うっかり!?でtry-catch で await を忘れると例外が捕捉されない!?

Last updated at Posted at 2024-05-30

はじめに

try-catch で await を使わないと例外が捕捉されない落とし穴に出会うことがあります。
うっかり await をつけ忘れるとどうなるのか、具体的なコード例を使って解説します。

try-catch では await しないと捕捉できない

⭕️ 正常系のコード (await あり)

import 'dart:async';

// 1秒待ってから例外をスローする非同期関数
Future<String> fetch() async {
  await Future.delayed(Duration(seconds: 1));
  throw Exception('エラーが発生しました');
}

Future<String> fetchItems() async {
  try {
    return await fetch();
  } on Exception catch (e) {
    // 例外はここで捕捉されます
    print('fetchItemsでキャッチしたエラー: $e');
    return 'エラー発生';
  }
}

void main() async {
  try {
    final result = await fetchItems();
    print('Fetched result: $result');
  } catch (e) {
    // 例外はここまで伝播しません
    print('main関数でキャッチしたエラー: $e');
  }
}

実行結果

このコードを実行すると、以下の出力が得られます。

fetchItemsでキャッチしたエラー: Exception: エラーが発生しました
Fetched result: エラー発生

fetchItems 内で例外が捕捉され、正しく処理されていることがわかります。

❌ 問題の発生例 (await なし)

次に、await を使わない場合の問題が発生するコードを見てみましょう。

import 'dart:async';

Future<String> fetch() async {
  await Future.delayed(Duration(seconds: 1));
  throw Exception('エラーが発生しました');
}

Future<String> fetchItems() async {
  try {
    return fetch(); // awaitなし
  } on Exception catch (e) {
    print('fetchItemsでキャッチしたエラー: $e');
    return 'エラー発生';
  }
}

void main() async {
  try {
    final result = await fetchItems();
    print('Fetched result: $result');
  } catch (e) {
    print('main関数でキャッチしたエラー: $e');
  }
}

実行結果

このコードを実行すると、以下の出力が得られます。

main関数でキャッチしたエラー: Exception: エラーが発生しました

fetchItems 内で例外がキャッチされず、main 関数で例外が捕捉されていることがわかります。

どういうことか

公式では以下

In general, when writing asynchronous code, you should always await a future when it is produced, and not wait until after another asynchronous delay. That ensures that you are ready to receive any error that the future might produce, which is important because an asynchronous error that no-one is awaiting is an uncaught error and may terminate the running program.(Future<T> classより抜粋

訳:
一般的に、非同期コードを書くときは、futureが生成されたら常にそれを待つべきです。なぜなら、誰も待っていない非同期エラーは捕捉されないエラーであり、実行中のプログラムを終了させてしまう可能性があるからです。

解説

await を使わずに Future を返すと、その Future はすぐに返され、非同期処理がバックグラウンドで続行されます。例外が発生しても、try-catch ブロックはすでに終了しているため、例外をキャッチできません。結果として、例外は呼び出し元に伝播します。

これを防ぐためには、await を使って非同期処理が完了するのを待ち、その間に発生した例外を適切にキャッチする必要があります。

まとめ

await を使うことで、非同期処理が完了するのを待ち、その間に発生した例外を try-catch ブロック内で捕捉することができます。これにより、非同期処理中の例外を適切に処理し、プログラムが予期せず終了するのを防ぐことができます。

参考

1
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?