Post

Kotlin Nullable Types and Null Safety

Kotlin Nullable Types and Null Safety

Kotlin 기초: Nullable 타입과 Null 안전성

📦 Null이란 무엇인가?

Null이란 ‘값이 없음’ 또는 ‘값이 존재하지 않음’을 나타내는 특별한 값입니다. 변수라는 상자는 만들어졌지만, 아직 그 안에 아무것도 담기지 않은 상태를 의미합니다.

프로그래밍에서 null은 의도적으로 값이 비어있는 상태를 표현할 때 유용하지만, 동시에 NullPointerException과 같은 치명적인 오류의 원인이 되기도 합니다. 따라서 null이 될 수 있는 변수는 항상 신중하게 다루어야 합니다.

📌 Null이 발생할 수 있는 사례

  • 사용자 입력 값: 사용자가 폼에 아무것도 입력하지 않고 제출했을 경우.
  • 파일 읽기: 존재하지 않는 파일을 읽으려고 시도할 때.
  • 데이터베이스 조회: 데이터베이스에서 특정 조건에 맞는 데이터를 찾지 못했을 경우.

⚙️ Nullable 타입 (Nullable Type)

Nullable 타입이란 null 값을 가질 수 있는 변수 타입을 의미합니다.

Kotlin에서는 타입 이름 뒤에 물음표(?)를 붙여 해당 변수가 null이 될 수 있음을 명시적으로 선언합니다.

1
2
3
4
5
6
// 이 변수는 String 값 또는 null을 가질 수 있습니다.
val nullableValue: String? = null

// 이 변수는 오직 Int 값만 가질 수 있으며, null을 할당할 수 없습니다.
val nonNullableValue: Int = 10
// nonNullableValue = null // 컴파일 오류 발생!

❓ Nullable 타입이 필요한 이유

컴퓨터는 각 데이터 타입이 지원하는 고유한 기능(함수, 속성)을 알고 있습니다. 예를 들어, String 타입은 길이를 확인하는 .length 속성을 가지고 있습니다. 하지만 null은 아무런 속성이나 기능이 없는 ‘빈 값’이므로 .length와 같은 연산을 수행할 수 없습니다.

Kotlin은 이처럼 null이 될 수 있는 변수와 그렇지 않은 변수를 타입 시스템에서 명확히 구분하여, null에 대해 안전하지 않은 연산을 시도하는 것을 컴파일 시점에 막아줍니다.


🛡️ Kotlin의 Null 안전성 (Null Safety)

Null 안전성(Null Safety)NullPointerException(NPE) 오류를 코드에서 최대한 배제하기 위해 설계된 Kotlin의 핵심적인 언어 특징입니다.

🆚 Java와의 차이점

구분KotlinJava
기본모든 변수는 기본적으로 null을 허용하지 않습니다 (Non-nullable).모든 참조 타입 변수는 기본적으로 null이 될 수 있습니다 (Nullable).
처리null 가능성을 타입(?)으로 명시하고, 컴파일러가 null 처리를 강제하여 컴파일 시점에 오류를 잡습니다.개발자가 직접 if (variable != null)과 같은 코드로 실행 시점null 여부를 확인해야 합니다.
결과NullPointerException 발생 가능성이 현저히 낮아져 프로그램의 안정성이 크게 향상됩니다.개발자의 부주의로 인해 NullPointerException이 발생할 위험이 항상 존재합니다.

✍️ Nullable 타입 안전하게 다루기

Kotlin은 null이 될 수 있는 변수를 안전하게 사용하기 위한 여러 가지 편리한 연산자를 제공합니다.

  1. 조건문으로 직접 확인 (if 문) 가장 기본적인 방법으로, if를 사용해 null이 아님을 직접 확인합니다. 이 블록 안에서 변수는 null이 아님이 보장됩니다.
    1
    2
    3
    4
    
    val name: String? = "Kotlin"
    if (name != null) {
        println("이름의 길이는 ${name.length}입니다.") // if 블록 안에서는 스마트 캐스트(Smart Cast)됨
    }
    
  2. 세이프 콜 연산자 (?.) ?. 연산자는 변수가 null이 아닐 경우에만 뒤따르는 함수나 속성을 호출하고, null이라면 전체 표현식을 null로 반환합니다.
    1
    2
    
    val name: String? = null
    println(name?.length) // null 출력 (오류 발생하지 않음)
    
  3. 엘비스 연산자 (?:) 변수가 null일 때 사용할 기본값을 지정할 수 있습니다.
    1
    2
    3
    
    val name: String? = null
    val displayName = name ?: "Guest" // name이 null이면 "Guest"를 사용
    println(displayName) // Guest 출력
    
  4. Non-null 단언 연산자 (!!) 개발자가 해당 변수는 절대로 null이 아님을 100% 확신할 때 사용합니다. null임에도 이 연산자를 사용하면 NullPointerException이 발생합니다.

    ⚠️ 주의: !! 연산자는 null 가능성을 컴파일러에게 숨기는 것이므로, 예기치 못한 오류를 발생시킬 수 있습니다. 꼭 필요한 경우가 아니라면 사용을 지양하고 세이프 콜이나 엘비스 연산자를 사용하는 것이 좋습니다.

    1
    2
    
    val name: String? = "Kotlin"
    println(name!!.length) // 5 출력. 만약 name이 null이었다면 NPE 발생
    
This post is licensed under CC BY 4.0 by the author.