안녕하세요.
오늘은 코틀린의 runCatching과 Result 타입에 대해 알아보도록 하겠습니다.
📌 에러 처리
코틀린에서 에러 처리는 자바와 비슷하게 할 수 있습니다
- try-catch를 사용한 에러 처리
추가로, 코틀린은 함수형 스타일의 프로그래밍을 지원합니다
이와 같이 사용할 수 있는 문법으로 runCatching이 있습니다
📌 runCatching
Result<T> 타입으로 성공/실패를 포장해줍니다
- 예외가 발생하면 → Result.failure(exception)
- 성공하면 → Result.success(value)
✅ When?
아래 경우일 때 runCatching을 사용하면 좋습니다
- 연산의 결과를 체이닝하고, 각 단계에서의 예외를 일관되게 처리하고 싶을 때
- 함수형 프로그래밍 패러다임을 따르는 코드베이스에서 작업할 때
- 예외를 값으로 취급하여 이후 로직에서 유연하게 처리하고 싶을 때
✅ Code
fun riskyOperation(): String {
if (Math.random() > 0.5) {
throw RuntimeException("Something went wrong!")
}
return "Success!"
}
fun main() {
val result = runCatching { riskyOperation() }
result
.onSuccess { println("결과: $it") }
.onFailure { println("예외 발생: ${it.message}") }
}
✅ 내부 구현
runCatching의 내부 구현을 보면 아래와 같이 구성되어 있습니다
- try-catch와 Result의 조합으로 구성되어 있습니다
@InlineOnly
@SinceKotlin("1.3")
public inline fun <R> runCatching(block: () -> R): Result<R> {
return try {
Result.success(block())
} catch (e: Throwable) {
Result.failure(e)
}
}
📌 Result<T>
Result<T>의 실제 구현은 해당 링크를 들어가면 확인할 수 있습니다
kotlin/libraries/stdlib/src/kotlin/util/Result.kt at whyoleg/dokka2-sync-stdlib · JetBrains/kotlin
The Kotlin Programming Language. . Contribute to JetBrains/kotlin development by creating an account on GitHub.
github.com
복잡하게 구현되어 있지만, 이렇게 생각하면 쉽습니다
sealed class Result<out T> {
class Success<T>(val value: T) : Result<T>()
class Failure(val exception: Throwable) : Result<Nothing>()
}
- T타입의 결과가 있을 수도 있고,
- Throwable 예외가 있을 수도 있는 구조 입니다
🛠️ Result<T>를 다루는 다양한 방식
Result<T>와 함께 쓸 수 있는 다양한 함수들을 알아보겠습니다
간단한 runCatching 예제를 만들고, 이를 다양한 방식으로 활용해보겠습니다
fun divide(a: Int, b: Int) = runCatching { a / b }
✅ getOrNull()
성공하면 value, 실패하면 null을 반환합니다
fun main() {
println(divide(10, 2).getOrNull()) // 5
println(divide(10, 0).getOrNull()) // null
}
✅ getOrElse { }
실패했을 때 기본값을 지정할 수 있습니다
fun main() {
println(divide(10, 2).getOrElse { -1 } ) // 5
println(divide(10, 0).getOrElse { -1 } ) // -1
}
✅ onSuccess / onFailure
성공, 실패에 따른 분기 처리가 가능합니다
체이닝 방식으로 에러 핸들링을 지원합니다
fun main() {
divide(10, 0)
.onSuccess { println("Result: $it") }
.onFailure { println("Error: $it") }
// Error: java.lang.ArithmeticException: / by zero
}
✅ map
성공 값을 조작하고 싶을 때 사용합니다
fun main() {
println(divide(10, 2)
.map { it * 2 }
.getOrElse { -1 }
) // 10
println(divide(10, 0)
.map { it * 2 }
.getOrElse { -1 }
) // -1
}
✅ recover
실패 시 대체 값을 제공합니다
- Success<T> 타입으로 반환합니다
fun main() {
println(divide(10, 2)
.recover { 100 }
) // Success(5)
println(divide(10, 0)
.recover { 100 }
) // Success(100)
}
✅ recoverCatching
예외 중첩 처리가 가능합니다
fun functionA(): Result<String> {
return Result.failure(Exception("A에서 실패!"))
}
fun functionB(): Result<String> {
return Result.failure(Exception("B에서도 실패!"))
}
fun functionC(): Result<String> {
return Result.success("C에서 가져온 값")
}
fun main() {
val result = functionA()
.recoverCatching { functionB().getOrThrow() } // A가 실패하면 B 실행
.recoverCatching { functionC().getOrThrow() } // B도 실패하면 C 실행
println(result.getOrElse { "모든 시도 실패" }) // 출력: "C에서 가져온 값"
}
감사합니다
'Kotlin' 카테고리의 다른 글
[Kotlin] Contract (0) | 2025.04.03 |
---|---|
[Kotlin] Builder Pattern 대체하기 (0) | 2025.01.13 |
[Kotlin] Generic (3) - 그 외 (2) | 2024.12.19 |
[Kotlin] Generic (2) - 변성 (0) | 2024.12.10 |
[Kotlin] Generic (1) - 제네릭? (0) | 2024.12.10 |