Java21 でプレビュー公開された Unnamed Classes and Instance Main Methods

blog1.mammb.com


はじめに

Java21 で、JEP 445 Unnamed Classes and Instance Main Methods がプレビュー公開されました。

この JEP では以下を実現します。

  • Java言語の初心者に対して、小さなプログラミングの基本概念を学習しやすくする(クラス、パッケージ、モジュールといった大きな概念は必要ない)
  • 単純なプログラムをより簡素に書き始められるようにする

以下の Hello World は、

public class HelloWorld { 
    public static void main(String[] args) { 
        System.out.println("Hello, World!");
    }
}

unnamed class と instance main Method により、以下のように書くことができるようになります。

void main() {
    System.out.println("Hello, World!");
}

詳細について見ていきましょう。


instance main メソッド

instance main メソッド では、main メソッドの修飾子やコマンドライン引数を省略することができます。

main メソッドは以下のように選択されます。

  • 起動されたクラスの main メソッドに publicprotected、またはデフォルト(つまりパッケージ)のアクセスを許可する
  • 起動されたクラスに String[] パラメータを持つ static main メソッドが存在しないが、パラメータを持たない static main メソッドが存在する場合は、そのメソッドを呼び出す
  • 起動されたクラスが static main メソッドを持たないが、非 private の ゼロパラメータコンストラクタ (public, protected, または package アクセス) と非 private インスタンス main メソッドを持つ場合は、そのクラスのインスタンスを生成する。もしそのクラスに String[] パラメータを持つインスタンス main メソッドがあれば、そのメソッドを呼び出す。

これにより Hello World は以下のように簡素化することができます。

class HelloWorld { 
    void main() { 
        System.out.println("Hello, World!");
    }
}


unnamed class

unnamed class により class 宣言を暗黙とすることができます。

Javaコンパイラは、クラス宣言で囲まれていないメソッドを含むソース・ファイルに遭遇すると、そのようなメソッド/フィールド/クラスを、暗黙のうちに無名トップレベル・クラスのメンバとみなすようになりました。

unnamed class により Hello World は以下のように簡素化できます。

void main() {
    System.out.println("Hello, World!");
}

以下のようにメソッドやフィールドを定義することもできます。

String world = "World!";
String greeting() { return "Hello, " + world; }

void main() {
    System.out.println(greeting());
}

unnamed class は以下のように無名クラス宣言したものと同等です。

new Object() {
    // the unnamed class's body
}.main();

unnamed class には以下の制限があります。

  • 無名クラスは常に無名パッケージのメンバーとなる(無名パッケージは無名モジュールに含まれる)
  • finalであり、Object以外のクラスを拡張したり、インターフェースを実装したりすることはできない
  • 無名クラスは名前で参照することができないので、静的メソッドへの メソッド参照はできない
  • this キーワードは使用することができ、インスタンスメソッドへのメソッド参照は可能


クラス起動時には以下の順で最初に見つかったmainメソッドが呼び出されることになります。

  1. 起動したクラスで宣言された、プライベートでないアクセス(つまり、 publicprotected、または package)の static void main(String[] args) メソッド
  2. 起動したクラスで宣言された、プライベートでないアクセスの static void main() メソッド
  3. 起動したクラスで宣言された、またはスーパークラスから継承された、 非プライベートアクセスの void main(String[] args) インスタンスメソッド
  4. 起動したクラスで宣言された、またはスーパークラスから継承された、プライベートアクセスでない void main() インスタンスメソッド


プレビュー機能の有効化

本機能は、Java21 ではプレビュー公開となりますので、プレビュー機能を有効にする必要があります。

  • コンパイル javac --release 21 --enable-preview Main.java
  • 実行 java --enable-preview Main