🎯
Stream handleError method
Dart Stream handleError Method
Overview
handleError
メソッドは、Dartのストリームで発生したエラーを処理するためのメソッドです。try-catchの代替として使用でき、非同期処理におけるエラーハンドリングを柔軟に行うことができます。
/// # handleError メソッド
///
/// ## 概要
/// `handleError` メソッドは、Dartのストリームで発生したエラーを処理するためのメソッドです。
/// try-catchの代替として使用できます。
///
/// ## 構文
/// ```dart
/// Stream<T> handleError(
/// Function onError, {
/// bool test(dynamic error)?,
/// })
/// ```
///
/// ## パラメータ
/// - `onError`: エラーが発生した時に実行される関数
/// - `void Function(Object error)` または
/// - `void Function(Object error, StackTrace)`
/// - `test`: エラーをフィルタリングするための関数(オプション)
/// - 指定しない場合は、すべてのエラーが処理されます
///
/// ## 使用例
void main() {
// 基本的な使用例
Stream.periodic(const Duration(seconds: 1), (count) {
if (count == 2) {
throw Exception('エラーが発生しました');
}
return count;
}).take(4).handleError((error) => print('エラーを捕捉: $error')).listen(
(data) => print('データ: $data'),
onError: (error) => print('未処理のエラー: $error'),
);
// エラーフィルタリングの例
Stream.periodic(const Duration(seconds: 1), (count) {
if (count == 2) throw FormatException('フォーマットエラー');
if (count == 3) throw ArgumentError('引数エラー');
return count;
})
.take(5)
.handleError(
(error) => print('FormatExceptionを捕捉: $error'),
test: (error) => error is FormatException,
)
.listen(
(data) => print('データ: $data'),
onError: (error) => print('その他のエラー: $error'),
);
}
/// ## 注意点
/// - `handleError`は非同期のエラー処理に使用
/// - `test`関数を使用してエラーの種類を選択的に処理可能
/// - エラーを完全に無視する場合は、`onError`で何も実行しない
/// - スタックトレースが必要な場合は、適切な関数シグネチャを使用
///
/// ## ベストプラクティス
/// 1. 具体的なエラータイプの処理
/// 2. エラーメッセージの明確な記録
/// 3. 適切なエラー変換の実装
/// 4. エラーの選択的な処理
実行結果:
実際に使ってみるとエラーが発生する!
void main(List<String> args) {
try {
final stream = Stream.error(Exception('try-catchで捉えられない'));
stream.listen((event) => print(event));
} catch (e) {
print('try-catchで捉えられた: $e');
}
}
構文
Stream<T> handleError(
Function onError, {
bool test(dynamic error)?,
})
パラメータ詳細
onError
-
型:
Function
- 必須: Yes
- 説明: エラー発生時に呼び出される関数
-
対応シグネチャ:
void Function(Object error)
void Function(Object error, StackTrace stackTrace)
test
-
型:
bool Function(dynamic error)?
- 必須: No
- 説明: エラーをフィルタリングするための関数
- デフォルト: すべてのエラーを処理
動作の詳細説明
エラー処理のフロー
- ストリームでエラーが発生
-
test
関数が指定されている場合、エラーが条件に一致するか確認 -
onError
関数が呼び出される - エラー処理の結果に基づいて処理を継続または中断
スタックトレースの扱い
-
onError
がStackTrace
パラメータを受け取る場合、エラーの発生場所を特定可能 - スタックトレースが存在しない場合は
StackTrace.empty
が渡される
成功例
1. 基本的なエラーハンドリング
Stream.periodic(const Duration(seconds: 1), (count) {
if (count == 2) throw Exception('計画的なエラー');
return count;
})
.take(4)
.handleError((error) {
print('エラーを処理: $error');
// エラーを処理して続行
})
.listen(
(data) => print('受信: $data'),
onError: (error) => print('未処理のエラー: $error'),
);
// 出力:
// 受信: 0
// 受信: 1
// エラーを処理: Exception: 計画的なエラー
// 受信: 3
2. 特定のエラータイプのみを処理
Stream.periodic(const Duration(seconds: 1), (count) {
if (count == 2) throw FormatException('フォーマットエラー');
if (count == 3) throw ArgumentError('引数エラー');
return count;
})
.handleError(
(error) => print('FormatException: $error'),
test: (error) => error is FormatException,
)
.listen(
print,
onError: (error) => print('その他のエラー: $error'),
);
// 出力:
// 0
// 1
// FormatException: フォーマットエラー
// その他のエラー: ArgumentError: 引数エラー
失敗例と注意点
1. スタックトレース情報の損失
// 悪い例
Stream.periodic(Duration(seconds: 1), (count) {
if (count == 2) throw Exception('エラー');
return count;
})
.handleError((error) {
throw error; // スタックトレース情報が失われる
});
// 良い例
Stream.periodic(Duration(seconds: 1), (count) {
if (count == 2) throw Exception('エラー');
return count;
})
.handleError((error, stack) {
throw error; // スタックトレース情報が保持される
});
2. エラーの無限ループ
// 危険な例
Stream.periodic(Duration(seconds: 1), (count) {
if (count == 2) throw Exception('エラー');
return count;
})
.handleError((error) {
throw Exception('新しいエラー'); // 新しいエラーが発生し続ける
})
.handleError((error) {
// 最初のhandleErrorで投げられたエラーを処理
print(error);
});
3. 不適切なエラーフィルタリング
// 悪い例
.handleError(
(error) => print(error),
test: (error) => error.toString().contains('format'), // 文字列比較は危険
)
// 良い例
.handleError(
(error) => print(error),
test: (error) => error is FormatException, // 型チェックを使用
)
アドバンストパターン
1. エラーの変換
Stream.periodic(Duration(seconds: 1), (count) {
if (count == 2) throw FormatException('不正な形式');
return count;
})
.handleError((error) {
if (error is FormatException) {
return -1; // エラーを特定の値に変換
}
throw error; // その他のエラーは再スロー
});
2. 複数のエラーハンドラーの連鎖
stream
.handleError((error) {
if (error is FormatException) throw CustomError(error);
throw error;
})
.handleError((error) {
if (error is CustomError) {
// カスタムエラーの処理
return;
}
throw error;
});
ベストプラクティス
-
型安全性の確保
- 具体的なエラー型を使用
-
dynamic
の使用を最小限に
-
エラーの適切な変換
- ビジネスロジックに適したエラーへの変換
- エラー情報の保持
-
デバッグ情報の確保
- スタックトレースの保持
- ログ出力の充実
-
エラー回復戦略
- フォールバック値の提供
- リトライメカニズムの実装
一般的な使用シナリオ
-
APIリクエストのエラーハンドリング
fetchData() .handleError((error) { if (error is TimeoutException) { return cachedData; } throw error; });
-
ファイル操作のエラー処理
readFile() .handleError((error) { if (error is FileSystemException) { logger.error('ファイル読み込みエラー: $error'); return defaultContent; } throw error; });
-
データ変換処理のエラー処理
parseData() .handleError((error) { if (error is FormatException) { return fallbackFormat; } throw error; });
関連する概念
-
Stream.transform
: より複雑なストリーム変換 -
catchError
: Future用のエラーハンドリング -
async/await
のエラーハンドリング -
Zone
によるエラー処理
まとめ
handleError
は非同期処理におけるエラーハンドリングを柔軟に行うための強力なツールです。
適切に使用することで、より堅牢なアプリケーションを構築できます。
Discussion