코틀린에서 자주 등장하는 ?와 !!는 널 안전성(Null Safety) 과 관련된 아주 중요한 연산자입니다.

이 두 가지는 코틀린 문법에서 객체가 null(널) 이 될 수 있느냐, 없느냐를 명확히 표현하는 역할을 합니다.

1. ? (물음표 연산자, Nullable)

코틀린에서 타입 뒤에 ? 를 붙이면 null 값을 허용한다는 의미입니다.

즉, 이 변수가 널(값이 없는 상태) 이 될 수 있음을 명시적으로 표시합니다.

✅ 예시

var name: String? = "1hyung"  // String 타입인데 null도 허용
name = null                  // 가능 (name이 String?이기 때문)

만약 물음표(?) 없이 타입을 선언하면 널을 허용하지 않습니다:

var name: String = "1hyung"   // String 타입이고 절대 null 불가능
// name = null               // 컴파일 에러 발생! (null을 넣을 수 없음)

2. ?. (Safe Call 연산자)

널 허용 변수에 접근할 때, 변수의 값이 널이 아닌 경우에만 실행하도록 하는 연산자입니다.

만약 널이라면 에러가 나지 않고, 그냥 널을 반환합니다.

✅ 예시

val length = name?.length  // name이 null이 아니라면 length를, null이면 null을 반환
println(length)  // name이 "1hyung"면 5, null이면 null 출력

이렇게 쓰면 안전하게 사용할 수 있습니다.

var name: String? = null
println(name?.uppercase())  // null 출력 (안전하게 처리됨)

3. ?: (엘비스 연산자, Elvis Operator)

이 연산자는 값이 널인 경우 대신 사용할 값을 지정하는 연산자입니다.
값이 널이면 우측 값을 대신 사용합니다.

✅ 예시

var name: String? = null
val length = name?.length ?: 0
println(length)  // 0 출력 (name이 null이라서 0 사용)

name = "1hyung"
println(name?.length ?: 0)  // 5 출력 (name이 null이 아니어서 name의 길이 사용)

즉, 값이 있을 때는 해당 값을 사용하고, 값이 없을 때만 오른쪽 값을 사용합니다.

4. !! (Not-null 단언 연산자, Non-null Assertion Operator)

!! 는 "이 값은 절대 null이 아니다!" 라고 개발자가 강제로 단언 하는 연산자입니다.

만약 이때 실제 값이 null이라면 실행할 때 (Runtime) NullPointerException (NPE) 이 발생하게 됩니다.

✅ 예시

var name: String? = "1hyung"
println(name!!.uppercase())  // "1hyung" 출력, 문제 없음!

name = null
println(name!!.uppercase())  // 실행 중 NullPointerException 에러 발생!

즉, !! 연산자는 코틀린의 안정적인 널 처리를 무시하고 강제로 Java처럼 에러 위험성을 감수하는 연산자입니다.
가급적이면 사용을 지양해야 하지만, 정말로 이 값이 절대 널이 될 수 없다고 확신할 때만 사용하는 게 좋습니다.

실제로 자주 쓰이는 실용적인 예시

다음과 같이 실제 코틀린 코드에서 활용됩니다:

// 사용자 입력이 있을 수도, 없을 수도 있을 때 사용
fun printUserInput(input: String?) {
    val safeInput = input ?: "입력이 없습니다."  // 입력 없을 때 기본값 지정
    println("입력값: $safeInput")
}

// 절대 null이면 안되는 값에서 사용 (사용 주의!)
fun forceNonNull(name: String?) {
    println("이름 길이: ${name!!.length}")  // name이 null이면 런타임 에러 발생!
}

// 안전한 호출 예시 (널이어도 에러 안남)
fun safeUpperCase(name: String?) {
    println(name?.uppercase() ?: "이름이 없습니다.")  // null이면 기본 문자열 출력
}

Q. 코틀린에서 ?, !! 연산자는 각각 언제 쓰이고 어떻게 동작하나요?
A. ? (물음표)는 코틀린에서 널을 허용하는 Nullable 타입을 나타낼 때 사용합니다. 즉, 타입 뒤에 ?를 붙이면 그 변수는 null값을 가질 수 있습니다. 그리고 변수가 null일 때를 대비해서 ?. (Safe call) 연산자로 안전하게 호출할 수 있습니다.

반면에 !! (느낌표 두 개)는 '이 값은 절대 null이 아니다' 라고 강제로 단언할 때 사용하는 연산자입니다. 그러나 만약 실제 값이 null이라면 실행 시점에 NullPointerException이 발생합니다.

따라서 !!는 가능하면 지양하고, 확실히 null이 아닌 경우에만 사용하는 게 좋습니다.

요약 정리

연산자의미예시주의사항
?널 허용(Nullable) 타입 선언var name: String?널 가능성 있음
?.안전 호출(Safe Call)name?.length널일 때 안전
?:널일 때 기본값 지정 (엘비스 연산자)name ?: "기본값"널 처리 기본값 지정
!!널이 아님을 강제 선언name!!.length널일 때 런타임 에러
profile
이유가 많은 사람보다 (자기)개발자가 되고싶은 1hyung입니다.

0개의 댓글