IntelliJ IDEA を使用した Kotlin Flow のデバッグ – チュートリアル
このチュートリアルでは、Kotlin Flow を作成し、IntelliJ IDEA を使用してデバッグする方法を説明します。
このチュートリアルは、コルーチンおよび Kotlin Flow の概念に関する事前の知識があることを前提としています。
Kotlin Flow の作成
低速なエミッター(emitter)と低速なコレクター(collector)を持つ Kotlin Flow を作成します。
IntelliJ IDEA で Kotlin プロジェクトを開きます。プロジェクトがない場合は、作成してください。
Gradle プロジェクトで
kotlinx.coroutinesライブラリを使用するには、build.gradle(.kts)に以下の依存関係を追加します。kotlindependencies { implementation("org.jetbrains.kotlinx:kotlinx-coroutines-core:1.10.2") }groovydependencies { implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-core:1.10.2' }その他のビルドシステムについては、
kotlinx.coroutinesの README の指示を参照してください。src/main/kotlinにあるMain.ktファイルを開きます。srcディレクトリには Kotlin のソースファイルとリソースが含まれています。Main.ktファイルには、Hello World!を出力するサンプルコードが含まれています。3 つの数値を流す(flow)を返す
simple()関数を作成します。- CPU を消費するブロッキングコードを模倣するために
delay()関数を使用します。これはスレッドをブロックすることなく、コルーチンを 100 ミリ秒中断(suspend)させます。 emit()関数を使用して、forループ内で値を生成します。
kotlinimport kotlinx.coroutines.* import kotlinx.coroutines.flow.* import kotlin.system.* fun simple(): Flow<Int> = flow { for (i in 1..3) { delay(100) emit(i) } }- CPU を消費するブロッキングコードを模倣するために
main()関数のコードを変更します。runBlocking()ブロックを使用してコルーチンをラップします。collect()関数を使用して、放出された値を収集します。- CPU を消費するコードを模倣するために
delay()関数を使用します。これはスレッドをブロックすることなく、コルーチンを 300 ミリ秒中断させます。 println()関数を使用して、Flow から収集した値を出力します。
kotlinfun main() = runBlocking { simple() .collect { value -> delay(300) println(value) } }Build Project をクリックしてコードをビルドします。

コルーチンのデバッグ
emit()関数が呼び出されている行にブレークポイントを設定します。
画面上部の実行構成の横にある Debug をクリックして、デバッグモードでコードを実行します。

Debug ツールウィンドウが表示されます:
- Frames タブにはコールスタックが含まれます。
- Variables タブには現在のコンテキスト内の変数が含まれます。ここでは、Flow が最初の値を放出(emit)していることがわかります。
- Coroutines タブには、実行中または中断中のコルーチンに関する情報が含まれます。

Debug ツールウィンドウの Resume Program をクリックしてデバッガーセッションを再開します。プログラムは同じブレークポイントで停止します。

今度は Flow が 2 番目の値を放出します。

最適化された変数 (Optimized-out variables)
suspend 関数を使用している場合、デバッガーで変数の名前の横に "was optimized out" というテキストが表示されることがあります。

このテキストは、その変数の生存期間(lifetime)が短縮され、変数がもう存在しないことを意味します。 最適化された変数があるコードは、値が見えないためデバッグが困難です。 コンパイラオプション -Xdebug を使用することで、この挙動を無効にできます。
プロダクション環境では絶対にこのフラグを使用しないでください:
-Xdebugは メモリリークを引き起こす可能性 があります。
並行して実行されるコルーチンの追加
src/main/kotlinのMain.ktファイルを開きます。エミッターとコレクターを並行して実行するようにコードを強化します。
- エミッターとコレクターを並行して実行するために
buffer()関数の呼び出しを追加します。buffer()は放出された値を保存し、別のコルーチンで Flow コレクターを実行します。
kotlinfun main() = runBlocking<Unit> { simple() .buffer() .collect { value -> delay(300) println(value) } }- エミッターとコレクターを並行して実行するために
Build Project をクリックしてコードをビルドします。
2 つのコルーチンを使用した Kotlin Flow のデバッグ
println(value)の行に新しいブレークポイントを設定します。画面上部の実行構成の横にある Debug をクリックして、デバッグモードでコードを実行します。

Debug ツールウィンドウが表示されます。
Coroutines タブで、2 つのコルーチンが並行して実行されていることが確認できます。
buffer()関数により、Flow のコレクターとエミッターは別々のコルーチンで実行されます。buffer()関数は、Flow から放出された値をバッファリングします。 エミッターコルーチンは RUNNING 状態であり、コレクターコルーチンは SUSPENDED 状態です。Debug ツールウィンドウの Resume Program をクリックしてデバッガーセッションを再開します。

今度は、コレクターコルーチンが RUNNING 状態になり、エミッターコルーチンが SUSPENDED 状態になります。
それぞれのコルーチンをさらに深く掘り下げて、コードをデバッグすることができます。
