아이템 05. 예외를 활용해 코드에 제한을 걸어라

아이템 05. 예외를 활용해 코드에 제한을 걸어라

예외를 활용해 코드에 제한을 걸어라 #

" 확실하게 어떤 기능으로(형태로) 동작해야 하는 코드가 있다면, 예외를 활용해 제한을 걸어주는 것이 좋습니다. “

예외(제한)을 통해 가독성, 빠른 실패의 이점을 취할 수 있겠다.

코틀린에서는 제한을 걸 때 아래 기능을 사용할 수 있다.

기능설명
requireargument 를 대상으로 한다.

argument에 제한을 건다.
check상태를 대상으로 한다.

상태를 확인(제한)할 때 사용할 수 있다.
assert말 그대로 assertion

assert 블록은 테스트 모드에서만 작동한다. (?, 밑에 내용을 살펴보면 코틀린/JVM에서만 테스트 코드가 아닌 곳에서 사용할 수 있다고 한다.)
?:return, throw 와 함께 활용한다.

require #

fun hello(name: String) {
    require(name.isNotBlank()) { "$name은 빈 문자열이 될 수 없어요." }
}

보통 함수(메서드)의 맨 앞에 배치된다. (= 무의식중에 대부분이 이렇게 사용할 것이다.)

require 는 조건을 만족하지 못할 때 IllegalArgumentException 을 발생시킨다.

즉, argument를 위한 기능이라는 것을 알 수 있다.


check #

fun write(): T {
    check(isOpen)
    ...
}

check 는 조건을 만족하지 못할 때 IllegalStateException 을 발생시킨다.

즉, state 를 위한 기능이라는 것을 알 수 있다.

check 함수도 아래와 같이 argument 를 체크하기 위해 사용할 수도 있다.

fun hello(name: String) {
    check(name.isNotBlank()) { "$name은 빈 문자열이 될 수 없어요." }
}

하지만 check 함수는 require 함수와 비슷하지만, 상태가 올바른지 확인할 때 사용해야한다. (require 도 마찬가지다.)


assert 계열 함수 #

@Test
fun `테스트 코드`() {
    val stack = Stack(20) { it }
    val ret = stack.pop(10)
    assertEquals(10, ret.size)
}
fun pop(num: Int = 1): List<T> {
    // ...
    assert(ret.size == num)
    return ret
}

위 코드는 코틀린/JVM에서만 활성화된다. (-ea JVAM 옵션을 활성화해야 확인할 수 있다.)

/**
 * Throws an [AssertionError] calculated by [lazyMessage] if the [value] is false
 * and runtime assertions have been enabled on the JVM using the *-ea* JVM option.
 */
@kotlin.internal.InlineOnly
public inline fun assert(value: Boolean, lazyMessage: () -> Any) {
    if (_Assertions.ENABLED) {
        if (!value) {
            val message = lazyMessage()
            throw AssertionError(message)
        }
    }
}

?: #

fun send(name: String?) {
    val receiverName = name ?: "알 수 없는 수신자"
    ...
}

?: + return/throw 구문은 굉장히 많이 사용되는 관용적인 방법이다. 적극적으로 활용해보는 것을 권장한다.

(추가적으로 권장하는 것) 함수의 앞부분에 넣어서 잘 보이게 만드는 것이 좋다.


요약 #

기능설명
requireargument
checkstate
assertassertion
?:?: + return/throw