이전포스팅에서 예상 못한 상황에서는 예외를 사용하라고 말하였습니다. 그렇지만 예외를 사용하는 것이 모든 상황에 알맞은 것은 아닙니다. 예외는 잘못된 특정된 상황에 사용해야 하지만 예를 들어 내트워크 문제나 텍스트 파싱시 텍스트 형식이 맞지 않은 경우 같이 함수가 원하는 결과를 만들어 낼 수없을 때에는 이러한 예외는 부적절할 수 있습니다.
- 많은 개발자가 예외를 전파되는 과정을 추적하지 못합니다.
- 코틀린의 모든 예외는 unchecked 예외입니다. 따라서 사용자가 예외를 처리하지 않을 수도 있으며, 이와 관련된 내용은 문서에도 제대로 드러나지 않습니다. 실제로 API를 사용할 때 예외와 관련된 사항을 단순하게 메서드등을 사용하면서 파악하기 힘듭니다.
- 예외는 예외적인 상황을 처리하기 위해서 만들어졌으므로 명시적인 테스트만큼 빠르게 동작하지 않습니다.
- try-catch 블록 내부에 코드를 배치하면 컴파일러가 할 수 있는 최적화가 제한됩니다.
그렇다면 위처럼 함수가 원하는 결과를 만들어 낼 수 없는 경우에는 어떻게 대처를 해야 할까요? 책에서는 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이나 엘비스 연사자로 널 안전성을 쉽게 유지할 수 있습니다.
val person = userText.readObjectOrNull<Person>()
val age = when(person) {
is Success -> person.age
is Failure -> -1
}
Result 같은 공용체(union type)를 리턴하기로 했다면 when 표현식을 써서 위방식처럼 처리할 수 있습니다. 이 방법은 try-catch 블록보다 효율적이고 사용하기 쉽고 더 명확합니다. 예외는 놓칠 수도 있고 전체 애플리케이션을 중지시킬 수도 있지만 null 값과 sealed Result 클래스는 명시적으로 처리해야 하며 애플리케이션의 흐름을 중지하지도 않습니다.
'코틀린 > Effective Kotlin' 카테고리의 다른 글
[Effective Kotlin] 9. 안정성 - use를 사용하여 리소스를 닫아라 (0) | 2023.08.01 |
---|---|
[Effective Kotlin] 8. 안정성 - 적절하게 null을 처리하라 (0) | 2023.07.28 |
[Effective Kotlin] 6. 안정성 - 사용자 정의 오류보다는 표준 오류를 사용 하라 (0) | 2023.07.21 |
[Effective Kotlin] 5. 안정성 - 예외를 활용해 코드에 제한을 걸어라 (0) | 2023.07.19 |
[Effective Kotlin] 4. 안정성 - inferred 타입으로 리턴하지 말라 (0) | 2023.07.17 |