반응형
Notice
Recent Posts
Recent Comments
Link
«   2024/09   »
1 2 3 4 5 6 7
8 9 10 11 12 13 14
15 16 17 18 19 20 21
22 23 24 25 26 27 28
29 30
Tags
more
Archives
Today
Total
관리 메뉴

안드로이드 개발자 노트

[이펙티브 코틀린] Item7. 결과 부족이 발생할 경우 null과 Failure를 사용하라 본문

Kotlin/이펙티브 코틀린

[이펙티브 코틀린] Item7. 결과 부족이 발생할 경우 null과 Failure를 사용하라

어리둥절범고래 2023. 9. 3. 16:28
반응형

함수가 원하는 결과를 만들어 낼 수 없을 때가 있습니다.

 

  • 서버로부터 데이터를 읽어 들이려고 했는데, 인터넷 연결 문제로 읽어 들이지 못한 경우
  • 조건에 맞는 첫 번째 요소를 찾으려 했는데, 조건에 맞는 요소가 없는 경우
  • 텍스트를 파싱해서 객체를 만들려고 했는데, 텍스트의 형식이 맞지 않는 경우

 

이러한 상황을 처리하는 메커니즘은 두 가지가 있습니다.

 

  • null 또는 '실패를 나타내는 sealed 클래스'를 리턴한다.
  • 예외를 throw한다.

 

여기서 예외는 정보를 전달하는 방법으로 사용해서는 안되며, 이유를 정리하면 다음과 같습니다.

 

  • 예외가 전파되는 과정을 제대로 추적하지 못한다.
  • 코틀린의 모든 예외는 unchecked(반드시 처리하게 강제되는 예외)이다.
  • 예외는 예외적인 상황을 처리하기 위해서 만들어졌으므로 명시적인 테스트만큼 빠르게 동작하지 않는다.
  • try-catch 블록 내부에 코드를 배치하면, 컴파일러가 할 수 있는 최적화가 제한된다.

 

반면, null과 Failure는 예상되는 오류를 표현할 때 명시적이고, 효율적이며, 간단한 방법으로 처리할 수 있습니다.

충분히 예측할 수 있는 범위의 오류는 null과 Failure를 사용하고, 예측하기 어려운 예외적인 범위의 오류는 예외를 throw해서 처리하는 것이 좋습니다.

 

간단한 예를 살펴봅시다.

 

inline fun <reified T> String.readObjectOrNull(): T? {
    //...
    if (incorrectSign) {
        return null
    }
    //...
    return result
}

inline fun <reified T> String.readObject(): Result<T> {
    //...
    if (incorrectSign) {
        return Failure(JsonParsingException())
    }
    //...
    return Success(result)
}

sealed class Result<out T>
class Success<out T>(val result: T): Result<T>()
class Failure(val throwable: Throwable): Result<Nothing>()

class JsonParsingException: Exception()

 

null을 처리해야 한다면, 사용자는 safe call 또는 Elvis 연산자 같은 다양한 널 안정성 기능을 활용합니다.

Result와 같은 공용체(union type)를 리턴하기로 했다면, when 표현식을 사용해서 처리합니다.

 

val age = userText.readObjectOrNull<Person>()?.age ?: -1
val person = userText.readObjectOrNull<Person>()
val age = when(person) {
    is Success -> person.age
    is Failure -> -1
}

 

null 값과 sealed result 클래스는 명시적으로 처리해야 하며, 어플리케이션의 흐름을 중지하지도 않습니다.

추가적인 정보를 전달해야 한다면 sealed result 클래스를 사용하고, 그렇지 않으면 null을 사용하는 것이 일반적입니다.

반응형