코틀린 Flow 공식문서 읽기 스터디 5차

Mendel·2023년 11월 21일
0

이번 범위

Flow Completion

플로우 수집이 완료되면(그게 정상적으로든 아니면 예외적으로든) 어떤 특정 작업을 해야하는 경우가 있을 수 있다.
이런 작업을 위해서 명령형과 선언형 두 가지 방법이 존재한다.

명령형) finally block

굳이 try/catch로 예외를 잡기 위한 목적이 아니더라도 수집기는 try/finally를 사용해서 수집이 완료됐을때 하고 싶은 일을 수행하게 만들 수 있다.

fun simple(): Flow<Int> = (1..3).asFlow()

fun main() = runBlocking<Unit> {
    try {
        simple().collect { value -> println(value) }
    } finally {
        println("Done")
    }
}       

1
2
3
Done

선언형) onCompletion 중간 연산자

선언적인 접근 방식으로는, onCompletion이라는 중간 연산자가 제공된다. 이 중간 연산자는 플로우가 완전히 수집이 끝났을 때 실행된다.

fun simple(): Flow<Int> = (1..3).asFlow()

simple()
    .onCompletion { println("Done") }
    .collect { value -> println(value) }

1
2
3
Done

onCompletion의 장점은 이것만이 아니다. 람다로 Throwable? 타입의 매개변수를 받는다. 때문에 이 수집이 정상종료인지 예외에 의한 종료인지를 알 수 있다.

아래 예제는 1을 방출하고 예외를 던진다. 그리고 onCompletion으로 예외에 의한 수집 종료인지를 판단할 수 있는 로직이다.

fun simple(): Flow<Int> = flow {
    emit(1)
    throw RuntimeException()
}

fun main() = runBlocking<Unit> {
    simple()
        .onCompletion { cause -> if (cause != null) println("Flow completed exceptionally") }
        .catch { cause -> println("Caught exception") }
        .collect { value -> println(value) }
}       

1
Flow completed exceptionally
Caught exception

여기서 catch라인을 제거해보고 실행해보면 터지는 것을 알 수 있다.
즉, onCompletion은 예외를 처리해주지는 않는다. 다만, 이게 정상종료인지 아닌지를 람다의 매개변수를 통해 알 수 있게만 해준다.

Successful completion

catch 중간 연산자와 onCompletion 중간 연산자와의 또다른 차이점은 다음과 같다. catch는 다운 스트림에서 발생한 예외는 잡지 못한다. 하지만 onCompletion은 다운 스트림 예외에 대해서도 실행이 되며 널이 아닌 값을 람다의 매개변수로 받게된다. (그렇다고 예외가 처리되지는 않는다)

명령형 vs 선언형

이 두가지 방법을 오늘 배웠는데, 둘 다 정상적인 종료와 예외종료에 대해 처리할 수 있습니다. 공식문서에서는 저희 스스로 코드 스타일과 선호도에 따라서 선택해 사용하라고 합니다 :)


참고
https://kotlinlang.org/docs/flow.html#flow-completion

profile
이것저것(안드로이드, 백엔드, AI, 인프라 등) 공부합니다

0개의 댓글