Tiny Star
본문 바로가기
Dev Log/Kotlin

[Kotlin] 안전한 코드를 위한 최소 요구사항 검증! require, check, assert 총정리

by 별터 2026. 1. 2.

개발을 하다 보면 "이 함수에는 절대 음수가 들어오면 안 돼", "이 시점에는 반드시 초기화가 되어 있어야 해" 같은 필수 조건들이 생깁니다.

 

이런 조건들을 처리할 때, 매번 if (x < 0) throw Exception(...)을 쓰고 계셨나요? 코틀린에서는 이런 '방어적 프로그래밍Defensive Programming)'을 위해 아주 멋진 표준 함수들을 제공합니다. 바로 requirecheckassert 입니다.


1. 인자값 검증의 정석: require()

 

함수를 호출할 때 넘겨받은 파라미터(Argument)가 유효한지 검사할 때 사용합니다. 조건이 맞지 않으면 IllegalArgumentException 을 발생시킵니다.

 

- 용도: 호출자가 값을 잘못 줬다고 알릴 때

- 위치: 보통 함수의 맨 윗줄.

fun setAge(age: Int) {
    // [Before] if문 사용
    if (age < 0) {
    	throw IllegalArgumentException("나이는 0보다 커야 합니다.")
        
    // [After] require 사용 ✨
    require(age >= 0) { "나이는 0보다 커야 합니다. 입력된 값: $age" }
    
    println("나이 설정 완료: $age")
}

 

장점:

    1. 코드가 훨씬 간결해집니다.

    2. 이 함수가 어떤 값을 필요로 하는지 명확하게 보여줍니다(문서화 효과).

    3. 스마트 캐스팅(Smart Casting)을 도와줍니다. (null 체크 등)


2. 상태 검증의 정석: check()

 

파라미터는 정상인데, 현재 객체의 상태(State)가 작업을 수행하기에 적절하지 않을 때 사용합니다.

조건이 맞지 않으면 IllegalStateException을 발생시킵니다.

 

- 용도: 해당 작업을 할 수 있는 상태가 아닐 때

- 예시: 초기화가 안 됐는데 사용하려 할 때, 로그인이 안 됐는데 글을 쓰려 할 때.

 

class Car {
    var isEngineOn = false
    
    fun accelerate() {
        // 시동이 켜져 있어야만 가속 가능
        check(isEngineOn) { "시동을 먼저 켜주세요." }
        
        println("부웅~ 속도를 올립니다.")
    }
}

3. 치명적인 오류: error()

로직상 절대 도달해서는 안 되는 코드에 도달했을 때, 강제로 에러를 발생시킵니다.

val input = "UNKNOWN"

val result = when(input) {
    "A" -> 1
    "B" -> 2
    else -> error("예상치 못한 입력값입니다!") // IllegalStateException 발생
}

4. null 검증: requireNotNullcheckNotNull

 

변수가 null인지 아닌지 검사하고, null이 아니면 그 값을 반환해 줍니다.

fun printName(name: String?) {
    // name이 null이면 Exception 발생, 아니면 non-null 타입으로 변환
    val validName = requireNotNull(name) { "이름은 필수입니다." }
    
    // 여기서부터 validName은 String? 이 아니라 String 타입입니다.
    println(validName.length)
}

5. 테스트 코드에서의 assert()

 

assert()는 앞선 함수들과 다르게, JVM-ea (Enable Assertions) 옵션이 켜져 있을 때만 동작합니다. 주로 테스트나 디버깅 목적의 내부 검증용으로 사용됩니다. 실제 배포(Production) 환경에서는 무시됩니다.

fun calculate(a: Int, b: Int): Int {
    val result = a + b
    // 배포 시에는 검사하지 않음 (성능 영향 X)
    assert(result > 0) { "결과는 양수여야 함" }
    return result
}

정리: 무엇을 써야 할까?

함수 발생하는 예외 언제 사용하는가?
require IllegalArgumentException 인자값이 올바른지 검사할 때 (가장 많이 씀)
check IllegalStateException 현재 상태가 올바른지 검사할 때
error IllegalStateException 절대 오면 안 되는 곳에 왔을 때
assert AssertionError 개발 단계에서 내부 로직을 검증할 때

 

코틀린의 이런 함수들을 적극적으로 사용하면, 에러를 조기에 발견하고(Fail Fast) 더 견고한 애플리케이션을 만들 수 있습니다. 지금 바로 if-throw 코드를 require로 바꿔보세요!