1 ポイント 投稿者 GN⁺ 2024-08-04 | 1件のコメント | WhatsAppで共有

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 機能がある

1件のコメント

 
GN⁺ 2024-08-04
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にこの機能を適用できるのかという質問

    • レガシーコードにどう適用できるのかについての疑問
  • 関連リンク