예외를 활용해 코드에 제한을 걸어라 #
" 확실하게 어떤 기능으로(형태로) 동작해야 하는 코드가 있다면, 예외를 활용해 제한을 걸어주는 것이 좋습니다. “
예외(제한)을 통해 가독성, 빠른 실패의 이점을 취할 수 있겠다.
코틀린에서는 제한을 걸 때 아래 기능을 사용할 수 있다.
기능 | 설명 |
---|---|
require | argument 를 대상으로 한다. 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 구문은 굉장히 많이 사용되는 관용적인 방법이다. 적극적으로 활용해보는 것을 권장한다.
(추가적으로 권장하는 것) 함수의 앞부분에 넣어서 잘 보이게 만드는 것이 좋다.
요약 #
기능 | 설명 |
---|---|
require | argument |
check | state |
assert | assertion |
?: | ?: + return/throw |