흐름 예외 처리
흐름 캡처는 이미터 또는 연산자의 코드가 예외를 throw하는 경우 예외와 함께 완료될 수 있습니다.
예외를 처리하는 방법에는 여러 가지가 있습니다.
컬렉터 캡처 시도
수집기는 Kotlin에서 예외를 처리하는 가장 좋은 방법입니다.
시도하다/잡다 블록을 사용할 수 있습니다:
fun simple(): Flow<Int> = flow {
for (i in 1..3) {
println("Emitting $i")
emit(i) // emit next value
}
}
fun main() = runBlocking<Unit> {
try {
simple().collect { value ->
println(value)
check(value <= 1) { "Collected $value" }
}
} catch (e: Throwable) {
println("Caught $e")
}
}
완전한 코드는 여기에서 찾을 수 있습니다
이 코드 모으다 터미널 연산자 내부에서 예외를 성공적으로 포착한 후 더 이상 값이 인쇄되지 않습니다.
Emitting 1
1
Emitting 2
2
Caught java.lang.IllegalStateException: Collected 2
모든 것이 갇혀있다
이전 예제는 이미 터, 중간 또는 터미널 연산자 내의 모든 예외를 포착합니다.
예를 들어 반환된 값을 문자열에 매핑하도록 코드를 변경하면 코드에서 예외가 발생합니다.
fun simple(): Flow<String> =
flow {
for (i in 1..3) {
println("Emitting $i")
emit(i) // emit next value
}
}
.map { value ->
check(value <= 1) { "Crashed on $value" }
"string $value"
}
fun main() = runBlocking<Unit> {
try {
simple().collect { value -> println(value) }
} catch (e: Throwable) {
println("Caught $e")
}
}
완전한 코드는 여기에서 찾을 수 있습니다
예외는 여전히 포착되어 더 이상 수집되지 않습니다.
*1
Emitting 1
string 1
Emitting 2
Caught java.lang.IllegalStateException: Crashed on 2
다음 내용은 독자의 이해를 돕기 위해 번역자가 추가한 내용입니다.
*하나. 예상치 못한 곳에서 예외가 발생하면 원하는 결과를 얻기 어렵기 때문에 문제가 된다.
이 문서는 공식 코루틴 문서를 번역한 것입니다.
원래의: 비동기 흐름 – 흐름 예외
원본 텍스트의 최종 편집: 2022년 9월 28일
예외 투명성
그렇다면 이미터의 코드는 예외 처리 동작을 어떻게 캡슐화할 수 있습니까?
흐름은 예외에 대해 투명해야 합니다.
시도하다/잡다 블록 내부 흐름 { … } 빌더 값을 내보내면 예외 투명성을 위반합니다.
이렇게 하면 예외를 throw하는 수집기가 항상 이전 예제와 같습니다.
시도하다/잡다예외를 잡는 데 사용할 수 있습니다.
이미 터 잡다 예외 투명성을 유지하고 예외 처리를 캡슐화하는 연산자입니다.
잡다 연산자의 본문은 예외를 구문 분석하고 포착된 예외에 따라 다른 방식으로 반응할 수 있습니다.
- 예외는 던지다로 다시 던질 수 있습니다.
- 잡다본문에서 방출하다값을 포함하여 예외를 방출로 전환할 수 있습니다.
- 예외는 다른 코드에서 무시하거나 기록하거나 처리할 수 있습니다.
예를 들어 예외를 포착하는 부분에서 텍스트를 인쇄해 보겠습니다.
*하나
simple()
.catch { e -> emit("Caught $e") } // emit on exception
.collect { value -> println(value) }
완전한 코드는 여기에서 찾을 수 있습니다
투명한 폐쇄
예외의 투명성 존중 잡다 중간 연산자는 업스트림 예외만 포착합니다(잡다 위 연산자의 예외만 포착하고 아래 예외는 포착하지 않습니다.
만약에 모으다 { … } 내부 블록(catch 아래의 코드)이 예외를 throw하면 예외가 catch되지 않습니다.
fun simple(): Flow<Int> = flow {
for (i in 1..3) {
println("Emitting $i")
emit(i)
}
}
fun main() = runBlocking<Unit> {
simple()
.catch { e -> println("Caught $e") } // does not catch downstream exceptions
.collect { value ->
check(value <= 1) { "Collected $value" }
println(value)
}
}
완전한 코드는 여기에서 찾을 수 있습니다
잡다 교환원이 있어도 “Caught…”라는 메시지가 뜨지 않는다.
Emitting 1
1
Emitting 2
Exception in thread "main" java.lang.IllegalStateException: Collected 2
at ...
선언적 캐치
모으다 오퍼레이터의 몸 각각에 안쪽으로 이동 잡다 뒤에 연산자를 넣으면 잡다 연산자의 선언적 특성과 모든 예외를 처리하려는 욕구를 결합할 수 있습니다.
모으다()매개변수 없이 사용하면 흐름 모음을 생성할 수 있습니다.
simple()
.onEach { value ->
check(value <= 1) { "Collected $value" }
println(value)
}
.catch { e -> println("Caught $e") }
.collect()
완전한 코드는 여기에서 찾을 수 있습니다
이제 “Caught…” 메시지가 명시적으로 인쇄된 것을 볼 수 있습니다.
시도하다/잡다 모든 예외는 블록을 사용하지 않고 잡을 수 있습니다.
Emitting 1
1
Emitting 2
Caught java.lang.IllegalStateException: Collected 2
다음 내용은 독자의 이해를 돕기 위해 번역자가 추가한 내용입니다.
*하나. 이 코드의 출력은 다음과 같습니다.
Emitting 1
string 1
Emitting 2
Caught java.lang.IllegalStateException: Crashed on 2
2가 발생하면 check(value <= 1)에 의해 불법 상태 예외가 발생하지만 catch 블록에서 이 예외가 포착된 후 "Caught java.lang.IllegalStateException: Crashed on 2"로 다시 발생합니다.
이 문서는 공식 코루틴 문서를 번역한 것입니다.
원래의: 비동기 흐름 – 예외 투명성
원본 텍스트의 최종 편집: 2022년 9월 28일