카테고리 없음

Kotlin 널 안전성 (Null Safety)

임베디드 친구 2024. 12. 20. 08:42
반응형

Kotlin은 Java와 달리 널 참조(Null Reference)로 인한 문제를 방지하기 위해 강력한 널 안전성 기능을 제공합니다. 오늘은 널 안전성의 기본 개념부터 Nullable과 Non-nullable 타입, Elvis 연산자, 그리고 널 처리 방법에 대해 알아보겠습니다.

널 참조는 프로그래밍에서 오류의 중요한 원인 중 하나입니다. "널 포인터 예외"는 개발자가 코드를 작성하면서 가장 많이 만나는 런타임 오류 중 하나이며, 이를 방지하기 위해 Kotlin은 명시적인 널 처리 메커니즘을 제공합니다.

Nullable과 Non-nullable 타입

Kotlin에서는 기본적으로 모든 변수는 Non-nullable입니다. 즉, 변수를 초기화할 때 널 값을 할당할 수 없고, 해당 변수는 항상 실제 값을 가지도록 강제됩니다. 이는 프로그램 실행 중 널 참조로 인해 발생하는 오류를 미리 예방할 수 있는 강력한 장치입니다.

예를 들어, 다음과 같은 코드를 보겠습니다.

var name: String = "Kotlin"
name = null  // 컴파일 오류 발생

위 코드는 name 변수에 널 값을 할당하려고 시도하면서 컴파일 오류가 발생합니다. Kotlin은 변수에 널 할당을 방지하기 위해 기본적으로 모든 변수를 Non-nullable로 처리합니다. 만약 변수가 널을 가질 수 있도록 하려면 타입 뒤에 ?를 붙여야 합니다.

var name: String? = "Kotlin"
name = null  // 정상 작동

String? 타입은 String 값이나 null을 가질 수 있는 Nullable 타입입니다. 이를 통해 명시적으로 널 가능성을 표현할 수 있습니다.

Null 처리 방법

Nullable 타입의 변수를 사용할 때는 반드시 널 처리를 해줘야 합니다. Kotlin은 안전한 널 처리를 위해 다양한 기능을 제공합니다.

1. 안전한 호출 연산자 (?.)

안전한 호출 연산자는 Nullable 타입의 변수를 사용할 때 널 체크를 자동으로 해줍니다. 변수 뒤에 ?.를 붙이면 해당 변수의 값이 널이 아닐 경우에만 그 뒤의 메서드나 프로퍼티에 접근하게 됩니다.

val length: Int? = name?.length

위 코드에서 name이 널인 경우, name?.length는 널을 반환하고, 널이 아닌 경우에만 length를 반환합니다. 이를 통해 널 체크를 간편하게 할 수 있습니다.

2. 엘비스 연산자 (?:)

엘비스 연산자는 Nullable 타입의 값이 널일 경우에 대체 값을 지정하는 데 사용됩니다. 널을 허용하는 변수를 사용할 때, 해당 값이 널인 경우에 대비해 기본값을 설정할 수 있습니다.

val length: Int = name?.length ?: 0

위 코드에서 name?.length가 널인 경우, length 변수에는 0이 할당됩니다. 엘비스 연산자는 널 값을 처리하는 데 매우 유용하게 사용됩니다.

3. 널 아님 단언 (!!)

널 아님 단언 연산자인 !!를 사용하면 해당 값이 절대 널이 아니라고 Kotlin에게 단언할 수 있습니다. 만약 단언한 값이 널일 경우, 런타임에서 NullPointerException이 발생하게 됩니다.

val length: Int = name!!.length

이 방식은 값이 절대 널이 아님을 확신할 때 사용할 수 있지만, 잘못 사용하면 런타임 오류를 발생시킬 수 있으므로 주의가 필요합니다.

Nullable과 Non-nullable 타입의 사용 예제

아래는 Nullable과 Non-nullable 타입을 활용한 예제입니다.

fun main() {
    var nullableName: String? = "Kotlin"
    var nonNullableName: String = "Hello"

    // 안전한 호출 연산자 사용
    println(nullableName?.length)  // 출력: 6

    // 엘비스 연산자 사용
    val length = nullableName?.length ?: -1
    println("Length: $length")  // 출력: Length: 6

    // 널 아님 단언 사용
    nullableName = null
    try {
        println(nullableName!!.length)  // NullPointerException 발생
    } catch (e: NullPointerException) {
        println("널 포인터 예외 발생: ${e.message}")
    }
}

위 예제에서는 nullableName이라는 Nullable 타입의 변수를 사용하여 널 처리 방법을 다양하게 보여주고 있습니다. 안전한 호출 연산자와 엘비스 연산자를 사용하여 널을 안전하게 처리하고, 널 아님 단언을 사용했을 때 NullPointerException이 발생하는 것을 확인할 수 있습니다.

요약

Kotlin의 널 안전성은 개발자가 널 포인터 예외를 사전에 방지하고 안정적인 코드를 작성할 수 있도록 돕는 중요한 기능입니다. Nullable과 Non-nullable 타입을 명확히 구분하고, 안전한 호출 연산자(?.), 엘비스 연산자(?:), 널 아님 단언(!!) 등을 적절히 활용하여 코드를 작성하면, 널로 인한 오류를 최소화할 수 있습니다.

다음과 같은 널 처리 방식을 습득하고 사용하는 것이 코틀린의 기본이자, 코드를 더 안전하게 만드는 길입니다. 앞으로 Kotlin을 사용하면서 널 안전성을 염두에 두고 코드를 작성해 보세요. 널 안전성을 적절히 활용하면 유지보수와 디버깅이 쉬운, 더욱 견고한 소프트웨어를 개발할 수 있을 것입니다.

반응형