💻 프로그래밍

Null

값이 없음을 나타내는 특별한 값. NullPointerException의 원인이며 Tony Hoare의 "Billion Dollar Mistake"로 불리는 프로그래밍 개념.

📖 상세 설명

Null은 프로그래밍에서 "값이 없음(absence of value)"을 나타내는 특수한 값입니다. 변수가 어떤 객체도 참조하지 않거나, 아직 초기화되지 않았거나, 의도적으로 비어있음을 표현할 때 사용됩니다. 데이터베이스에서는 "알 수 없는 값"이나 "적용 불가능한 값"을 표현하는 데 사용되며, 0이나 빈 문자열("")과는 명확히 다른 의미를 가집니다.

Null 참조(Null Reference)는 컴퓨터 과학자 Tony Hoare가 1965년 ALGOL W 언어를 설계하면서 도입했습니다. 그는 2009년 QCon 컨퍼런스에서 이를 "Billion Dollar Mistake(10억 달러짜리 실수)"라고 불렀습니다. null 참조로 인해 지난 40년간 발생한 수많은 버그, 보안 취약점, 시스템 충돌이 최소 10억 달러의 비용을 유발했다는 의미입니다.

JavaScript에서는 null과 undefined라는 두 가지 "값이 없음"을 나타내는 값이 존재합니다. null은 개발자가 의도적으로 "값이 없음"을 할당한 경우를 나타내며, undefined는 변수가 선언되었지만 아직 값이 할당되지 않은 상태를 나타냅니다. 이 두 값은 == 비교에서는 같지만 === 비교에서는 다릅니다.

현대 프로그래밍 언어들은 Null Safety(널 안전성)를 위한 다양한 접근 방식을 제공합니다. Java 8+의 Optional, Kotlin의 Nullable Types(?), Swift의 Optional, Rust의 Option 등이 대표적입니다. 이들은 컴파일 타임에 null 가능성을 명시하고, null을 다룰 때 안전한 방법을 강제함으로써 런타임 NullPointerException을 방지합니다.

💻 코드 예제

Java - null 체크 패턴들
// 1. 전통적인 null 체크
public String getUserName(User user) {
    if (user != null) {
        if (user.getName() != null) {
            return user.getName();
        }
    }
    return "Anonymous";
}

// 2. Optional 사용 (Java 8+)
public String getUserNameSafe(User user) {
    return Optional.ofNullable(user)
            .map(User::getName)
            .orElse("Anonymous");
}

// 3. Objects.requireNonNull - 방어적 프로그래밍
public void processUser(User user) {
    Objects.requireNonNull(user, "User must not be null");
    // user가 null이면 NullPointerException 발생
}
JavaScript - null vs undefined
// null vs undefined 비교
let a;                    // undefined (선언만 함)
let b = null;            // null (의도적으로 비움)

console.log(a == b);      // true  (느슨한 비교)
console.log(a === b);     // false (엄격한 비교)

// Optional Chaining (?.) - ES2020
const userName = user?.profile?.name ?? "Anonymous";

// Nullish Coalescing (??) - null/undefined만 처리
const count = inputCount ?? 0;  // 0이나 ""는 그대로 사용
const count2 = inputCount || 0; // 0이나 ""도 0으로 대체
Kotlin - Null Safety
// Kotlin의 Nullable Types
var name: String = "John"   // null 불가
var nullableName: String? = null  // null 가능

// Safe call operator (?.)
val length = nullableName?.length  // null이면 null 반환

// Elvis operator (?:)
val len = nullableName?.length ?: 0  // null이면 0

// Not-null assertion (!!) - 권장하지 않음
val forceLength = nullableName!!.length  // NPE 발생 가능

// let을 이용한 null 체크
nullableName?.let {
    println("Name length: ${it.length}")
}

🗣 실무 대화 예시

🔍 코드 리뷰: NullPointerException 방지
👨‍💻
시니어 개발자 (리뷰어)
이 코드에서 user.getAddress().getCity() 부분이 위험해 보이네요. user나 address가 null일 수 있는 상황에서 NullPointerException이 발생할 수 있습니다. 어떻게 수정하면 좋을까요?
👩‍💻
주니어 개발자
아, 맞아요. Optional을 사용해서 Optional.ofNullable(user).map(User::getAddress).map(Address::getCity).orElse("Unknown")으로 수정하면 될 것 같습니다. 아니면 메서드 시작 부분에서 Objects.requireNonNull로 빨리 실패하도록 할 수도 있을 것 같은데요.
👨‍💻
시니어 개발자 (리뷰어)
좋은 접근이에요! Optional 체인이 더 깔끔하겠네요. 그리고 가능하다면 도메인 모델 자체에서 address가 Optional로 선언되어 있는지 확인해보세요. API 설계 단계에서 null 가능성을 명시하는 게 가장 좋은 방어입니다.

🎓 기술 면접: Null 처리 전략
👤
면접관
Tony Hoare가 null을 "Billion Dollar Mistake"라고 했는데, 왜 그렇게 말했을까요? 그리고 현대 언어들은 이 문제를 어떻게 해결하려고 하나요?
👩
지원자
null 참조는 런타임에 NPE를 발생시켜 시스템 장애를 일으키고, 이를 방지하려면 방어적 null 체크 코드가 필요해서 코드 복잡도가 올라갑니다. 수십 년간 이로 인한 버그 수정, 시스템 다운타임, 보안 취약점 비용이 막대했죠.
👩
지원자
해결책으로 Kotlin은 타입 시스템에서 String?처럼 nullable을 명시하고 컴파일러가 강제합니다. Rust는 null 자체가 없고 Option<T>로 값의 존재 여부를 표현해요. Java는 Optional을 도입했지만 기존 코드와의 호환성 때문에 강제는 못 하고 있습니다.
👤
면접관
좋습니다. 그럼 실무에서 null을 다룰 때 본인만의 원칙이 있다면요?
👩
지원자
첫째, 메서드는 가능하면 null을 반환하지 않고 빈 컬렉션이나 Optional을 반환합니다. 둘째, public 메서드 파라미터는 시작 부분에서 requireNonNull로 빠르게 실패시킵니다. 셋째, 필드는 생성자에서 초기화하여 null 상태를 최소화합니다.

주의사항

🚨 Null 관련 실무 주의사항
  • NullPointerException (NPE): 가장 흔한 런타임 예외입니다. 프로덕션에서 NPE가 발생하면 서비스 장애로 이어질 수 있으므로, 코드 리뷰와 정적 분석 도구(@Nullable, @NonNull 어노테이션)를 활용하세요.
  • Optional 남용 금지: Optional은 반환 타입으로 사용하기 위해 설계되었습니다. 필드 타입, 메서드 파라미터, 컬렉션 요소로 사용하면 오히려 복잡도가 올라갑니다. Optional.get()을 직접 호출하는 것도 피하세요.
  • 방어적 코딩: 외부 API, 데이터베이스, 사용자 입력에서 오는 데이터는 항상 null일 수 있다고 가정하세요. "이 값은 절대 null이 아니다"라는 가정은 위험합니다.
  • null vs 빈 값 구분: 빈 문자열("")과 null, 빈 리스트와 null은 의미가 다릅니다. "값이 없음"과 "빈 값이 있음"을 명확히 구분하여 사용하세요.
  • 데이터베이스 NULL: SQL에서 NULL은 "알 수 없음"을 의미하며, NULL = NULL은 false입니다. IS NULL, COALESCE, NULLIF 함수를 적절히 사용하세요.

🔗 관련 용어

📚 더 배우기