Flow 수집 완료 처리하기
flow 수집이 완료되면(정상적으로 혹은 예외가 발생되어서), 완료에 따른 동작을 실행해야 할 수 있다. 이미 알 수도 있듯이, 이는 명령적인 방식 혹은 선언적인 방식 두가지 방식으로 실행될 수 있다.
명령적인 finally 블록
try/catch에 더해서, 수집기는 collect 동작이 완료됨에 따라 동작을 실행하는 finally 블록을 사용할 수 있다.
fun simple(): Flow<Int> = (1..3).asFlow()
fun main() = runBlocking<Unit> {
try {
simple().collect { value -> println(value) }
} finally {
println("Done")
}
}
📌 전체 코드는 이곳에서 확인할 수 있습니다.
이 코드는 simple Flow에 의해 생성되는 3개의 숫자를 프린트하고 마지막에 "Done" 문자열을 출력한다 :
1
2
3
Done
선언적인 처리
선언적으로 접근하면, flow는 flow의 수집이 완료되었을 때 실행되는 onCompletion 중간 연산자가 있다.
이전 예제를 onCompletion 연산자를 사용해 다시 작성할 수 있고, 이는 같은 결과를 출력한다.
simple()
.onCompletion { println("Done") }
.collect { value -> println(value) }
📌 전체 코드는 이곳에서 확인할 수 있습니다.
onCompletion의 중요한 이점은 수집 작업이 정상적으로 혹은 예외적으로 완료되었는지를 확인하는데 사용할 수 있는 람다식의 nullable한 Throwable 파라미터이다. 다음 예제에서 simple Flow는 1을 방출한 다음 예외를 발생시킨다 :
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 연산자는 예외를 처리하지 않는다. 위의 예제 코드에서 확인할 수 있듯이 예외는 여전히 다운스트림으로 흐른다*1. 이는 이후의 onCompletion 연산자로 전달되며, catch 연산자를 사용해 처리될 수 있다.
성공적인 완료
catch 연산자와 또 다른 점은 onCompletion은 모든 예외를 볼 수 있고, 업스트림 Flow가 취소나 실패 없이 성공적으로 완료되었을 때 null 예외를 수신한다는 것이다.
fun simple(): Flow<Int> = (1..3).asFlow()
fun main() = runBlocking<Unit> {
simple()
.onCompletion { cause -> println("Flow completed with $cause") }
.collect { value ->
check(value <= 1) { "Collected $value" }
println(value)
}
}
📌 전체 코드는 이곳에서 확인할 수 있습니다.
다운스트림 예외로 인해 Flow가 중단되었기 때문에, 완료의 원인이 null이 아닌 것을 확인할 수 있다 :
1
Flow completed with java.lang.IllegalStateException: Collected 2
Exception in thread "main" java.lang.IllegalStateException: Collected 2
📖 아래 내용은 독자의 이해를 위해 번역자가 추가한 글입니다.
*1. 다운스트림으로 전파되는 것을 뜻한다.
이 글은 Coroutines 공식 문서를 번역한 글입니다.
원문 : Asynchronous Flow - Flow completion
원문 최종 수정 : 2022년 9월 28일
Flow 명령적으로 다루기 vs 선언적으로 다루기
이제 우리는 어떻게 Flow를 수집하고, 명령적인 방식과 선언적인 방식으로 완료와 예외를 처리하는 방법을 안다. 자연적으로 어떤 접근 방식이 선호되고 왜 그런지에 대한 의문이 생길 것이다. 이에 대해 라이브러리적인 관점에서 특정한 접근 방식만을 옹호하지 않는다.*1 두 접근 방식 모두 유효하며, 선호도와 코스 스타일에 따라 선택되어야 한다.
📖 아래 내용은 독자의 이해를 위해 번역자가 추가한 글입니다.
*1. 라이브러리는 라이브러리가 사용하는 API만을 공개하며, 공개된 API를 어떻게 활용하는지는 개발자에게 달렸다.
이 글은 Coroutines 공식 문서를 번역한 글입니다.
원문 : Asynchronous Flow - Imperative versus declarative
원문 최종 수정 : 2022년 9월 28일
목차로 돌아가기