try-catchとrunCatching foldの違い
try-catchとは
try-catchはKotlinの言語機能として提供される例外処理機構である。tryブロック内で例外が発生する可能性のあるコードを実行し、catchブロックで例外を捕捉して処理する。finallyブロックを追加すれば、例外の発生に関わらずクリーンアップ処理を実行できる。例外はuncheckedのみで、コンパイル時にチェックされない。
runCatchingとfoldとは
runCatchingはKotlin標準ライブラリの関数で、指定されたブロックを実行し、成功時は結果をResultオブジェクトに封装して返す。失敗時はThrowableを捕捉し、Result.failureとして返す。foldはResultオブジェクトのメソッドで、onSuccessとonFailureのラムダを指定して成功時と失敗時の処理を定義する。これにより関数型スタイルで例外を扱える。
実装例
try-catchの実装例
以下は、整数除算でゼロ除算例外を扱う例である。
fun divide(a: Int, b: Int): Int { try { return a / b } catch (e: ArithmeticException) { println("ゼロ除算エラー: ${e.message}") return 0 } finally { println("処理終了") } } // 使用例 val result = divide(10, 0) // 出力: ゼロ除算エラー: / by zero, 処理終了, result=0
runCatching foldの実装例
同じ整数除算を関数型スタイルで扱う例である。
fun divide(a: Int, b: Int): Result<Int> = runCatching { a / b } val result = divide(10, 0).fold( onSuccess = { it }, onFailure = { println("ゼロ除算エラー: ${it.message}") 0 } ) // 出力: ゼロ除算エラー: / by zero, result=0
違い
try-catchは構造化された制御フローで、特定の例外タイプを複数catchブロックで扱える。finallyでリソース解放を保証する。一方、runCatchingはすべてのThrowableを捕捉し、Resultとして値を返すため、エラーをデータとして伝播可能。foldはResultを展開して処理を分岐させる。try-catchは即時処理向きで、runCatching foldはエラー遅延処理やチェーンに適する。
比較表
| 項目 | try-catch | runCatching fold |
|---|---|---|
| スタイル | 命令型。制御フローで例外を即時処理。 | 関数型。Resultオブジェクトでエラーを値として扱い、遅延処理可能。 |
| 例外捕捉 | 特定の例外タイプを複数catchで指定可能。 | すべてのThrowableを捕捉。特定の例外はfold内で分岐。 |
| クリーンアップ | finallyブロックで確実。 | 直感的でない場合あり。onFailure内で処理するか、別途実装。 |
| コードの簡潔さ | ボイラープレートが増えやすい。 | 簡潔でチェーン可能。 |
| 親和性 | 伝統的なプログラミングに適する。 | 関数型プログラミングやコルーチンに強い。 |
| パフォーマンス | 言語機能のため効率的。 | Resultオブジェクト生成で若干オーバーヘッド。 |
try-catchのメリット・デメリット
メリット
- 標準的で読みやすい。特定の例外を細かく扱える。
- finallyブロックでクリーンアップを確実に実行可能。
- 言語機能のため、ライブラリ依存がない。
デメリット
- ボイラープレートが増え、コードが冗長になりやすい。
- 関数型プログラミングとの親和性が低い。
runCatching foldのメリット・デメリット
メリット
- 簡潔で関数型。Resultを返してエラーを値として扱える。
- チェーン可能で、遅延処理向き。
- コルーチンや非同期処理でエラーを柔軟に伝播。
デメリット
- すべての例外を捕捉するため、意図しないエラーを隠蔽しやすい。
- finallyのようなクリーンアップが直感的でない場合がある。
- パフォーマンスがtry-catchより劣る可能性。