【Coroutinesガイド】IntelliJ IDEAを使ったFlowのデバッグ - チュートリアル

※ソース記事は[こちら](https://kotlinlang.org/docs/debug-flow-with-idea.html)
このチュートリアルでは、IntelliJ IDEAを使ってKotlin Flowを作り、デバッグする方法をデモする。
このチュートリアルは、読者が[コルーチン](https://kotlinlang.org/docs/coroutines-guide.html)と[Kotlin Flow](https://kotlinlang.org/docs/flow.html#flows)の概要を事前の知識を持つことを想定している。

::: note
デバッグは`kotlinx-coroutines-core`バージョン1.3.8以上で動作する。
:::
# Kotlin Flowの作成
遅いエミッターと遅いコレクタを持つKotlin [flow](https://kotlinlang.org/api/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines.flow/flow.html)を次のように作成する。
1. IntelliJ IDEAでKotlinプロジェクトを開く。プロジェクトが無い場合は、[新規作成](https://kotlinlang.org/docs/jvm-get-started.html#create-an-application)する。
1. `src/main/kotlin`内の`main.kt`を開く。
`src`ディレクトリには、Kotlinソースファイルとリソースが含まれている。`main.kt`ファイルには、`Hello World!`を出力するサンプルコードが含まれている。
1. 3つの数字のflowを返却する`simple()`関数を作る。
    - [delay](https://kotlinlang.org/api/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/delay.html)関数を使い、CPUを消費するブロッキングコードの真似をする。これはスレッドをブロックすることなく、100msの間、コルーチンをsuspendする。
    - `for`ループ内で、[emit](https://kotlinlang.org/api/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines.flow/-flow-collector/emit.html)関数を使い、値を生成する。
    ```Kotlin
    import kotlinx.coroutines.*
    import kotlinx.coroutines.flow.*
    import kotlin.system.*
    
    fun simple(): Flow<Int> = flow {
        for (i in 1..3) {
            delay(100)
            emit(i)
        }
    }
    ```
1. `main`関数内のコードを次のように変更する。
    - コルーチンをラップするために[runBlocking](https://kotlinlang.org/api/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/run-blocking.html)ブロックを使う。
    - [collect](https://kotlinlang.org/api/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines.flow/collect.html)関数を使い、放出された値を収集する。
    - [delay](https://kotlinlang.org/api/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/delay.html)関数を使い、CPUを消費するブロッキングコードの真似をする。これはスレッドをブロックすることなく、300msの間、コルーチンをsuspendする。
    - flowから収集された値を[println]()※ソース記事は[こちら](https://kotlinlang.org/docs/debug-flow-with-idea.html)
このチュートリアルでは、IntelliJ IDEAを使ってKotlin Flowを作り、デバッグする方法をデモする。
このチュートリアルは、読者が[コルーチン](https://kotlinlang.org/docs/coroutines-guide.html)と[Kotlin Flow](https://kotlinlang.org/docs/flow.html#flows)の概要を事前の知識を持つことを想定している。

::: note
デバッグは`kotlinx-coroutines-core`バージョン1.3.8以上で動作する。
:::
# Kotlin Flowの作成
遅いエミッターと遅いコレクタを持つKotlin [flow](https://kotlinlang.org/api/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines.flow/flow.html)を次のように作成する。
1. IntelliJ IDEAでKotlinプロジェクトを開く。プロジェクトが無い場合は、[新規作成](https://kotlinlang.org/docs/jvm-get-started.html#create-an-application)する。
1. `src/main/kotlin`内の`main.kt`を開く。
`src`ディレクトリには、Kotlinソースファイルとリソースが含まれている。`main.kt`ファイルには、`Hello World!`を出力するサンプルコードが含まれている。
1. 3つの数字のflowを返却する`simple()`関数を作る。
    - [delay](https://kotlinlang.org/api/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/delay.html)関数を使い、CPUを消費するブロッキングコードの真似をする。これはスレッドをブロックすることなく、100msの間、コルーチンをsuspendする。
    - `for`ループ内で、[emit](https://kotlinlang.org/api/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines.flow/-flow-collector/emit.html)関数を使い、値を生成する。
    ```Kotlin
    import kotlinx.coroutines.*
    import kotlinx.coroutines.flow.*
    import kotlin.system.*
    
    fun simple(): Flow<Int> = flow {
        for (i in 1..3) {
            delay(100)
            emit(i)
        }
    }
    ```
1. `main`関数内のコードを次のように変更する。
    - コルーチンをラップするために[runBlocking](https://kotlinlang.org/api/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/run-blocking.html)ブロックを使う。
    - [collect](https://kotlinlang.org/api/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines.flow/collect.html)関数を使い、放出された値を収集する。
    - [delay](https://kotlinlang.org/api/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/delay.html)関数を使い、CPUを消費するブロッキングコードの真似をする。これはスレッドをブロックすることなく、300msの間、コルーチンをsuspendする。
    - flowから収集された値を[println](https://kotlinlang.org/api/latest/jvm/stdlib/stdlib/kotlin.io/println.html)関数を使い、出力する。
    ```Kotlin
    fun main() = runBlocking {
        simple()
            .collect { value ->
                delay(300)
                println(value)
            }
    }
    ```
1. `プロジェクトのビルド`をクリックすることで、コードをビルドする。
![flow1](https://kotlinlang.org/docs/images/flow-build-project.png)
# コルーチンのデバッグ
1. `emit()`関数が呼び出される行にブレークポイントを設定する。
![flow2](https://kotlinlang.org/docs/images/flow-breakpoint.png)
1. 画面の上部の実行構成の隣にある`デバッグ`をクリックすることで、デバッグモードでコードを実行する。
![flow3](https://kotlinlang.org/docs/images/flow-debug-project.png)
`デバッグ`ツールウィンドウが現れる。
    - `フレーム`タブにはコールスタックが含まれている。
    - `変数`タブには現在のコンテキスト内の変数が含まれている。それにより、flowから最初の値が放出されているのがわかる。
    - `コルーチン`タブには、実行中あるいはsuspendされたコルーチン情報が含まれている。
![flow4](https://kotlinlang.org/docs/images/flow-debug-1.png)
1. `デバッグ`ツールウィンドウ内の`再開`をクリックすることで、デバッガーセッションを再開する。プログラムは同じブレークポイントで停止する。
![flow5](https://kotlinlang.org/docs/images/flow-resume-debug.png)
現在、flowは二番目の値を放出している。
![flow6](https://kotlinlang.org/docs/images/flow-debug-2.png)
# 並列に実行するコルーチンの追加
1. `src/main/kotlin`内の`main.kt`を開く。
1. エミッターとコレクターを並列に実行するようにコードを強化する。
    - [buffer](https://kotlinlang.org/api/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines.flow/buffer.html)関数呼び出しを追加し、エミッターとコレクターを並列で動作するようにする。`buffer`は放出された値を格納し、別のコルーチンでflowのコレクターを実行する。
    ```Kotlin
    fun main() = runBlocking<Unit> {
        simple()
            .buffer()
            .collect { value ->
                delay(300)
                println(value)
            }
    }
    ```
1. `プロジェクトのビルド`をクリックすることで、コードをビルドする。
# 二つのコルーチンを持つKotlin flowのデバッグ
1. `println(value)`に新しいブレークポイントを設定する。
1.  画面の上部の実行構成の隣にある`デバッグ`をクリックすることで、デバッグモードでコードを実行する。
![flow7](https://kotlinlang.org/docs/images/flow-debug-3.png)
`デバッグ`ツールウィンドウが現れる。
`コルーチン`タブ内に、並列に実行している二つのコルーチンを見ることができる。`buffer`関数のために、flowのコレクターとエミッターが別のコルーチンで実行されている。`buffer`関数はflowから放出された値をバッファリングする。エミッターのコルーチンは`RUNNING`状態を持ち、コレクターのコルーチンは`SUSPENDED`状態を持つ。
1. `デバッグ`ツールウィンドウ内の`再開`をクリックすることで、デバッガーセッションを再開する。
![flow8](https://kotlinlang.org/docs/images/flow-debug-4.png)
現在は、コレクターのコルーチンは`RUNNING`状態を持ち、一方エミッターのコルーチンは`SUSPENDED`状態を持つ。(※`emit`のブレークポイントではcoroutine2がACTIVEになり、`println(value)`のブレークポイントではcoroutine1がACTIVEになる)
IntelliJ IDEAのデバッガーを使うことで、自分のコードをデバッグするためにそれぞれのコルーチンを詳しく調べることができる。