HTTP 200 OK

Memento mori & Carpe diem

Kotlin

[Kotlin] Error Handling

sjoongh 2023. 8. 26. 17:15
  • kotlin Error Handle을 하기 전에 어떠한 상황에서 에러 상황을 처리할지 정해야 한다.
    • Type-safe Error Handling → Either Type
    • Either Type은 Left && Right에 특정 value가 들어갔을때 미리 정의한 type과 일치하지 않는다면 .left() && .right() 를 사용해 success/fail을 커스텀할 수 있다.
    sealed class Either<out L, out R>
    data class Left<L>(val value: L): Either<L, Nothing>() / error
    data class Right<R>(val value: R): Either<Nothing, R>() // success
    
  • Sealed class는 하나의 type value를 사용하는 제한적인 상황일때 다양한 기능을 해당 value로 구현해야 한다면 유용한 클래스이다.
  • 또한 sealed class는 상속(abstract) 클래스이다.
  • 그렇다면 sealed class와 enum 클래스의 차이점은 무엇인가?
    • 둘은 많은 부분에서 흡사하지만 단 한가지 다른점은 enum은 오직 single sample을 가지고 여러개의 subclass를 가질 수 없다는 점이다.

그렇다면 sealed class 를 어떤 경우에 사용하는가?

  • 다양한 경우에 활용할 수 있지만 user에게 요청이 들어왔을때 status를 보내주는 상황에서 사용할 수 있다. success/fail 을 구분해 정의하여 원하는 structure를 전달해 줄 수 있다.
  • 또한 sealed class를 결과값으로 만들기 위해서는 어떻게 사용해야 할까? repositry영역에 class를 정의해서 사용할 수도 있다.
interface FeedRepositry {
	fun getFeeds(): LiveData<List<Feed>>
}

 

Result vs runCatching

  • result와 runcatching은 활용되어지는 영역이 다르다. 먼저 result는 단순히 성공/실패를 구분할 수 밖에 없다
  • 다음은 result에 대한 예제이다
class JobService(private val jobs: Jobs) {

    fun printOptionJob(jobId: JobId) {
        val maybeJob: Result<Job?> = jobs.findById(jobId)
        if (maybeJob.isSuccess) {
            maybeJob.getOrNull()?.apply { println("Job found: $this") } ?: println("Job not found for id $jobId")
        } else {
            println("Something went wrong: ${maybeJob.exceptionOrNull()}")
        }
    }
}
  • getOrNull은 Result 또는 null을 returns 한다.
  • getOrThrow는 Result 또는 Result.Failure에 선언된 exception을 throw 한다.
  • getOrDefault는 Result 또는 Result에 default로 선언된 값을 failure값으로 returns 한다.

 

mapCatching

  • mapCatching function은 value 값을 변환시키거나 Result에 선언된 exception을 throw 해준다.
class CurrencyConverter {
    @Throws(IllegalArgumentException::class)
    fun convertUsdToEur(amount: Double?): Double =
        if (amount != null && amount >= 0.0) {
            amount * 0.91
        } else {
            throw IllegalArgumentException("Amount must be positive")
        }
}
  • 위 코드의 converter는 null이나 부정 값일 경우 throw 한다.

 

Recover
try {
    runCatching {
       throw Error("runBlock문 에러발생")
    }.recover { it: String ->
        throw Error("recover문 에러발생")
    }.onFailure {
        //에러가 전달되지않습니다.
    }
} catch (e: Exception) {
    //recover에서 발생한 에러가 받아집니다.
}

 

RecoverCatching
runCatching {
    throw Error("runBlock문 에러발생")
}.recoverCatching { it: String ->
    throw Error("recover문 에러발생")
}.onFailure {
    //이곳에서 에러를 받습니다.
}
  • runCatching이 성공할 경우 호출되었다면 recovery은 실패했을 경우 호출된다. 만약 runCatching 문에서 에러가 발생할 경우 recovery, recoverCatching 문이 호출된 후 onSuccess로 전달된다. 하지만 map 과 마찬가지로 블록 내에서 에러가 발생했을 경우 다르게 처리한다.
  • mapCatching 또한 블록 안의 에러를 내부에서 처리하며 onFailure로 받을 수 있다.

map & recovery

'Kotlin' 카테고리의 다른 글

JSON 직렬화가 왜 안돼?..  (1) 2024.11.24
[Kotlin] Result란?  (0) 2023.09.12
Run Catching  (0) 2023.03.01
[Kotlin] 기초  (0) 2022.08.01