1P by neo 2달전 | favorite | 댓글 1개

Null-Restricted and Nullable Types (Preview)

요약

Java 타입에 null을 허용하거나 거부하는 nullness 마커를 지원하는 미리보기 언어 기능.

목표

  • Java의 참조 타입을 개선하여 프로그래머가 null 참조를 기대하는지 여부를 표현할 수 있게 함
  • 다른 nullness 속성을 가진 타입 간의 변환을 지원하며, 잘못 처리된 null 값에 대한 경고 제공
  • 기존 Java 코드와 호환되며, 새로운 기능을 점진적으로 도입할 수 있도록 지원
  • null을 거부하는 타입의 변수를 처음 읽기 전에 초기화하도록 보장
  • 별도로 컴파일된 클래스에서도 null을 거부하는 타입을 런타임에 강제
  • 런타임 최적화를 위해 필요한 메타데이터와 무결성 보장 제공

비목표

  • 기존 코드를 자동으로 재해석하지 않음
  • 모든 null 값을 명시적으로 처리하도록 요구하지 않음
  • 기본 타입에 대한 변경 사항을 포함하지 않음
  • 표준 라이브러리에 언어 개선 사항을 적용하지 않음

동기

  • Java 프로그램에서 String 타입 변수는 String 객체 참조나 null 값을 가질 수 있음
  • 변수에 null을 허용할지 여부를 명확히 표현할 수 없어 혼란과 버그 발생
  • 개발자가 null 값을 지원하지 않거나 기대하는지를 타입의 일부로 명시할 수 있는 도구 제공 필요

설명

Nullness 속성과 마커

  • 참조 타입은 nullness를 선택적으로 표현할 수 있음
  • Foo!는 null을 포함하지 않는 null-restricted 타입
  • Foo?는 null을 포함하는 nullable 타입
  • 기본적으로 Foo의 nullness는 지정되지 않음

필드와 배열 초기화

  • null-restricted 필드나 배열은 사용 전에 반드시 초기화되어야 함
  • 초기화되지 않은 null-restricted 필드를 읽으려 하면 예외 발생

표현식 nullness와 변환

  • Java 컴파일러는 모든 표현식의 nullness를 결정
  • nullness 변환을 통해 다른 nullness를 가진 표현식을 다룰 수 있음
  • narrowing nullness 변환은 런타임에 NullPointerException을 발생시킬 수 있음

런타임 null 검사

  • narrowing nullness 변환이 발생하면 NullPointerException 발생

타입 변수의 nullness

  • 타입 변수도 nullness를 표현할 수 있음
  • null-restricted와 nullable 타입 변수는 제네릭 코드 내에서 특정 nullness를 주장

타입 인수와 경계

  • 타입 인수는 nullness를 표현할 수 있으며, 이는 API의 nullness에 영향을 미침
  • nullness가 일치하지 않는 타입 인수는 경고를 발생시킬 수 있음

메서드 오버라이딩과 타입 인수 추론

  • nullness는 메서드 시그니처가 동일한지 여부를 결정할 때 무시됨
  • 오버라이딩 메서드의 반환 타입은 nullness 변환을 통해 변환 가능

컴파일러 경고

  • null-restricted 타입을 만들면 새로운 컴파일 타임 오류가 발생할 수 있음
  • narrowing nullness 변환, null-hostile 연산에서 ? 타입 사용 등은 경고를 발생시킬 수 있음

컴파일 및 클래스 파일 표현

  • 대부분의 null 마커는 클래스 파일에서 제거됨
  • 새로운 NullRestricted 속성은 필드가 null 값을 허용하지 않음을 나타냄

코어 리플렉션

  • Foo!.classFoo?.class 리터럴은 존재하지 않음
  • 새로운 RuntimeType API는 런타임에 null-restricted 변형을 설명

보충 변경 사항

  • 전통적인 직렬화는 null-restricted 필드 및 배열과 호환되지 않음
  • javadoc은 nullness 마커를 포함
  • java.lang.reflect.Type 및 javax.lang.model API는 nullness를 인코딩

대안

  • Java 생태계의 다양한 개발 도구는 자체적으로 null 추적을 구현
  • 다른 프로그래밍 언어는 nullness를 타입 시스템에서 추적
  • 런타임 nullness 강제는 명시적 검사나 Objects.requireNonNull 호출로 구현 가능

종속성

  • Flexible Constructor Bodies (Second Preview) 필요
  • Null-Restricted Value Class Types (Preview)와 JEP 402: Enhanced Primitive Boxing (Preview)와 같은 향후 작업

GN⁺의 정리

  • 이 JEP는 Java에서 null 값을 명확히 처리할 수 있는 도구를 제공하여 코드의 안정성과 가독성을 높임
  • null-restricted와 nullable 타입을 도입하여 null 참조로 인한 버그를 줄일 수 있음
  • 기존 코드와 호환되며 점진적으로 도입할 수 있어 개발자에게 유연성을 제공
  • 다른 언어와의 비교에서 Java의 null 처리 능력을 강화할 수 있음
  • 비슷한 기능을 제공하는 도구로는 Kotlin의 null-safety 기능이 있음
Hacker News 의견
  • C#와 Kotlin의 null 처리 방식 비교

    • C#은 프로젝트에서 nullability를 활성화하면 모든 변수가 기본적으로 non-null로 선언됨
    • Kotlin도 비슷하지만, backwards compatibility가 필요하지 않음
    • Kotlin은 lateinit var 선언을 통해 초기화되지 않은 non-nullable 변수를 나중에 초기화할 수 있는 기능을 제공함
  • 새로운 제안에 대한 의견

    • 기존 변수들이 nullable, explicitly nullable, explicitly non-nullable로 구분됨
    • C#의 접근 방식이 더 나아 보임, 특히 레거시 코드베이스에서 nullability 문제를 해결할 필요가 없음
    • 그러나 C# 접근 방식은 코드베이스에서 nullability 문제를 즉시 강조함
  • nullness-narrowing 자동 변환에 대한 우려

    • 자동 변환이 잘못된 느낌을 줌
    • 컴파일러 오류를 발생시켜야 할 경우가 있음
    • 명시적인 변환이 더 안전함
  • 모든 변수를 기본적으로 non-null로 표시하는 방법 필요성

    • 패키지나 파일 수준에서 모든 변수를 non-null로 표시할 수 있는 방법이 필요함
    • 그렇지 않으면 T! 구문을 거의 모든 변수에 사용하게 되어 코드가 복잡해짐
  • Java에서 언어 수준의 명시적 optionality 기능 필요성

    • Kotlin과 Typescript에서의 경험을 바탕으로 언어 수준의 지원이 더 나음
    • Java의 NullAway 같은 도구는 번거로움
  • 표준 라이브러리에 언어 개선 사항을 적용하지 않는 결정에 대한 비판

    • PHP 사용 경험에서 표준 라이브러리와의 상호작용이 번거로움
    • 표준 라이브러리에 이러한 표현력을 추가하는 것이 필요함
  • 컴파일 타임 경고를 오류로 승격하는 쉬운 방법 필요성

    • Java는 주로 정적 타입 언어이므로 동적 동작을 도입하는 것은 좋지 않음
  • 기본적으로 non-nullable, immutable, 좁은 범위로 설정해야 하는 필요성

    • 새로운 디자인 결정이 즉각적인 편의성을 위해 안전한 경로를 포기하는 경우가 많음
    • 많은 언어와 기술에서 이러한 문제로 인해 많은 오류가 발생함
  • Hack 언어에서의 null 처리 경험

    • Hack의 타입 시스템에서 nullness가 중요한 부분임
    • nullable 배열에 대한 질문
    • Java에서는 모든 레거시 코드가 nullability를 가정하므로 문제가 됨
  • Java SDK에 이 기능을 적용할 수 있는지에 대한 질문

    • 레거시 코드에 대해 어떻게 적용할 수 있을지에 대한 의문
  • 관련 링크 제공