0Pricing
Kotlin Academy · レッスン

catchとonCompletion:Flowのエラー処理

上流で発生した例外を捕捉し、Flowの完了イベントに反応します。

「catchとonCompletion:Flowのエラー処理」はCoddyKit上の無料Kotlin Academyレッスンです。 これはレッスン2/4です。 下記で完全なレッスンを無料で読むことができます。その後、ブラウザ内の組み込みコードエディタと24時間対応のAIチューターでハンズオン演習できます。 これはKotlin Academy学習パスの一部であり、ウェブとCoddyKitアプリ全体で進捗が同期されます。 Kotlin Academyコースには全4レッスンが含まれています。

Flow の例外の基本

Flow 内で例外が発生すると、Flow は終了します。処理しなければ、例外は collector に伝播し、Flow は終了します。

import kotlinx.coroutines.*
import kotlinx.coroutines.flow.*
fun main() = runBlocking {
    try {
        flow {
            emit(1)
            throw RuntimeException("stream error")
            emit(2)
        }.collect { println(it) }
    } catch (e: Exception) {
        println("Caught: ${e.message}")
    }
}

catch 演算子

catch は upstream の例外を処理し、代替値を発行したり再スローしたりできます。ただし、collector 自体がスローした例外はキャッチしません。

import kotlinx.coroutines.*
import kotlinx.coroutines.flow.*
fun main() = runBlocking {
    flow {
        emit(1)
        throw RuntimeException("oops")
    }.catch { e ->
        println("Caught: ${e.message}")
        emit(-1)  // fallback value
    }.collect { println(it) } // 1, then -1
}

catch は upstream のみを処理する

catch が捕捉するのは Flow ビルダーと upstream 演算子からの例外だけで、collect lambda からの例外は捕捉しません。

import kotlinx.coroutines.*
import kotlinx.coroutines.flow.*
fun main() = runBlocking {
    try {
        flowOf(1, 2, 3)
            .catch { e -> println("upstream: ${e.message}") }
            .collect {
                if (it == 2) throw RuntimeException("collector error") // not caught by catch
                println(it)
            }
    } catch (e: Exception) {
        println("Collector exception: ${e.message}")
    }
}

catch での再スロー

例外を調べ、処理できないものだけを選択して再スローできます。

import kotlinx.coroutines.*
import kotlinx.coroutines.flow.*
fun main() = runBlocking {
    try {
        flow {
            emit(1)
            throw IllegalStateException("state error")
        }.catch { e ->
            if (e is RuntimeException) { emit(-1); return@catch }
            throw e  // rethrow unknown exceptions
        }.collect { println(it) }
    } catch (e: Exception) {
        println("Rethrown: ${e.message}")
    }
}

onCompletion 演算子

onCompletion は、Flow が正常に完了した場合も例外で終了した場合も実行されます。失敗時には cause パラメーターが null 以外になります。

import kotlinx.coroutines.*
import kotlinx.coroutines.flow.*
fun main() = runBlocking {
    flowOf(1, 2, 3)
        .onCompletion { cause ->
            if (cause == null) println("Completed normally")
            else println("Failed: ${cause.message}")
        }
        .collect { println(it) }
}

エラー時の onCompletion

onCompletion は upstream で例外が発生した場合にも実行されます。例外を cause として受け取りますが、例外を抑制することはありません。例外はそのまま伝播します。

import kotlinx.coroutines.*
import kotlinx.coroutines.flow.*
fun main() = runBlocking {
    try {
        flow {
            emit(1)
            throw RuntimeException("error")
        }.onCompletion { cause ->
            println("onCompletion cause=${cause?.message}")
        }.collect { println(it) }
    } catch (e: Exception) {
        println("outer catch: ${e.message}")
    }
}

catch と onCompletion の組み合わせ

catch で回復して代替値を発行し、その後 onCompletion で結果に関係なくログ出力やリソースの解放を行います。

import kotlinx.coroutines.*
import kotlinx.coroutines.flow.*
fun main() = runBlocking {
    flow {
        emit("ok")
        throw RuntimeException("network error")
    }.catch { e ->
        emit("fallback") // recover
    }.onCompletion {
        println("Stream done — release resources")
    }.collect { println(it) }
}

retry 演算子

retry(n) { ... } は、例外が発生した場合に n 回を上限として upstream Flow を再サブスクライブします。

import kotlinx.coroutines.*
import kotlinx.coroutines.flow.*
var attempt = 0
fun unstableFlow() = flow {
    attempt++
    if (attempt < 3) throw RuntimeException("attempt $attempt failed")
    emit("success on attempt $attempt")
}
fun main() = runBlocking {
    unstableFlow()
        .retry(3) { e -> println("retrying: ${e.message}"); true }
        .collect { println(it) }
}

カスタムロジックのための retryWhen

retryWhen は例外と試行回数を提供するため、バックオフを追加したり、リトライの対象とする例外を絞り込んだりできます。

import kotlinx.coroutines.*
import kotlinx.coroutines.flow.*
fun main() = runBlocking {
    var n = 0
    flow {
        if (n++ < 2) throw IOException("IO error")
        emit("done")
    }.retryWhen { cause, attempt ->
        cause is IOException && attempt < 3
    }.collect { println(it) }
}

onStart 演算子

onStart は最初の発行の前に実行されます。データが到着する前にローディング状態を表示したり、リソースを初期化したりする場合に便利です。

import kotlinx.coroutines.*
import kotlinx.coroutines.flow.*
fun main() = runBlocking {
    flowOf("data")
        .onStart { emit("Loading...") }
        .onCompletion { emit("Done") }
        .collect { println(it) }
}

実際の API 呼び出しでのエラーハンドリング

リポジトリのフローをcatchでラップして例外をドメインエラーに変換し、onCompletionでローディングインジケーターを非表示にします。

import kotlinx.coroutines.*
import kotlinx.coroutines.flow.*
sealed class State { object Loading : State(); data class Data(val v: String) : State(); data class Error(val msg: String) : State() }
fun apiFlow(): Flow<String> = flow { delay(50); emit("response") }
fun uiFlow(): Flow<State> = apiFlow()
    .map { State.Data(it) as State }
    .onStart { emit(State.Loading) }
    .catch { e -> emit(State.Error(e.message ?: "unknown")) }
fun main() = runBlocking { uiFlow().collect { println(it) } }

クイックチェック

catchオペレーターの主な制限は何ですか。

復習

catchは上流で発生した例外を処理し、フォールバック値を発行できます。onCompletionは、正常終了時でもエラー時でも必ず実行され、クリーンアップやログ出力に使用できます。これらをretry/retryWhenと組み合わせると、回復力のあるフローパイプラインを構築できます。

よくある質問

「catchとonCompletion:Flowのエラー処理」レッスンは無料ですか?

はい。「catchとonCompletion:Flowのエラー処理」の完全なテキストはこのウェブで無料で読めます。インタラクティブに演習し(組み込みコードエディタと24時間対応のAIチューター)、Kotlin Academyコースの残りをアンロックするには、CoddyKit PROにアップグレードしてください。 Kotlin Academyコースには全4レッスンが含まれています。

「catchとonCompletion:Flowのエラー処理」で何を学びますか?

上流で発生した例外を捕捉し、Flowの完了イベントに反応します。 ブラウザで直接実行するハンズオンコードでKotlin Academyを演習し、24時間対応のAIチューターがレッスンを進める中での質問に答えます。

Kotlin Academyを始めるのに経験は必要ですか?

事前経験は必要ありません。CoddyKitのKotlin Academyは初級者から上級者向けに構成されているため、ここから始めるか最初から始めて、自分のペースで進むことができます。 これはレッスン2/4です。

「catchとonCompletion:Flowのエラー処理」レッスンにはどのくらい時間がかかりますか?

ほとんどのCoddyKitレッスンは約5~10分かかります。各レッスンはコンパクトでインタラクティブなので、着実に進歩し、ウェブとアプリ全体で正確に前回の場所から再開できます。

このKotlin Academyレッスンでコードを書いて実行できますか?

はい。すべてのKotlin Academyレッスンに組み込みコードエディタが含まれているため、ブラウザでリアルコードを書いて実行し、即座のAIフィードバックを取得できます。ローカル設定は不要です。

このコースのすべてのレッスン

  1. Flow演算子:map、filter、transform、take
  2. catchとonCompletion:Flowのエラー処理
  3. combineとzip:複数のFlowを統合する
  4. flowOnとbuffer:コンテキストとバックプレッシャー
← Kotlin Academyに戻る