😇

Java23でリリースされた機能を触ってみた!!(下書き供養)

に公開

去年のアドベントカレンダー用に下書きしていた記事があったので供養します😇
(この記事自体は別の媒体で公開されました)
半年ちょっと前の記事ですが、読んでいてこんなことも知らなかったのか。。。と思う場面のちょこちょこあったのですが供養なのであえてそのままにしています🙇

現在は、JavaとTypeScript(React)で実装されたアプリケーションの開発案件に参画しています。

今回は、JJUG CCC 2024 Fallにスタッフ参加した時に、
Java23で実装されたコードのクイズがあって今まで触ってきたJavaとあまりにも雰囲気が変わっていたので、『これは触ってみなくては!!』と思い、
触ってみた記録としてこの記事を残しました!!
全ての機能までは記事にできなかったのですが、参考にしていただけますと幸いです。

【オンライン上で簡単にJava23を動かせる環境】

https://dev.java/playground/

では、早速触ってみましょう!!

ツール

JEP 467: Markdown Documentation Comments

https://openjdk.org/jeps/467

ドキュメントを翻訳すると、このようなことが記載されていました笑

HTML を書くのが面倒なので、きれいにフォーマットされたドキュメント コメントを書くのも面倒です。

今までの /** */ で書かなくてもよくなり、マークダウン形式で記載できるそうです。
具体的には『///』で開始して下記のようにして記述ができるようです!!

/// # Hello Class
/// 
/// This class serves as a demonstration of Markdown-enabled Javadoc comments.
///
/// ## Features
/// - Uses **Markdown** for formatting.
/// - Simplifies writing and improves readability.
///
/// ## Example Usage
/// ```java
/// Hello hello = new Hello();
/// hello.greet();
/// ```
///
/// @author Your Name
/// @version 1.0
/// @since 1.0
///
public class Hello {
  /// Prints a greeting message to the console.
  ///
  /// **Usage:**
  /// ```java
  /// hello.greet();
  /// ```
  ///
  public void greet() {
      System.out.println("Hello, world!");
  }
}

実際の動作確認をしてみたい時は、Java23が使用できる環境で
Hello.java(任意の名前の時はファイル名を置換してください)を作成して上記ソースをコピペして指定のHello.javaがある階層で下記コマンドを実行してみてください。

% javadoc -d docs Hello.java
% open docs/index.html

言語仕様

JEP 476: Module Import Declarations (Preview)

https://openjdk.org/jeps/476

ドキュメントにはこのような記載がありました。

Javaプラットフォームが進化するにつれて、List、Map、Stream、Pathといったクラスやインターフェースは、ほぼ不可欠な存在となりました。しかし、これらのクラスはjava.langには含まれていないため、自動的にインポートされることはありません。

確かに冒頭にめっちゃ大量のimport文書いてますよね・・・
要するにモジュールごとのimportができるようです。

import module java.base;

これを冒頭に記載すれば、
• java.util(List, Map, Streamなど)
• java.util.stream(Collectors, Streamなど)
• java.nio.file(Pathなど)
がまとめてimportされることになるそうです。
ですが、モジュール毎にまとめてimportしてしまうためコンフリクトのケアは必要です。。。。
例えば

import module java.base;
import module java.sql;

void main() {
    Date nowDate = new Date();
    println("Current date (java.util.Date): " + nowDate);
}

プレビュー機能なので

java --enable-preview

を使用して実行すると、
下記のようなコンパイルエラーになります。

test.java:5: エラー: Dateの参照はあいまいです
    Date nowDate = new Date();
    ^
  java.sqlのクラス java.sql.Dateとjava.utilのクラス java.util.Dateの両方が一致します
test.java:5: エラー: Dateの参照はあいまいです
    Date nowDate = new Date();
                       ^
  java.sqlのクラス java.sql.Dateとjava.utilのクラス java.util.Dateの両方が一致します
エラー2個
エラー: コンパイルが失敗しました

まんまなのですが、モジュール毎にまとめてimportしたため、どのモジュールのDateを使用したいのかが不明確のためコンパイルができていません。
このような場合は、下記のように記述してコンフリクトを回避するとのこと。

import java.util.List
または、
java.util.Date nowDate = new java.util.Date();

JEP 477: Implicitly Declared Classes and Instance Main Methods (Third Preview)

https://openjdk.org/jeps/477

Java プログラミング言語は、最初の言語として意図されたものでもあります。プログラマーが最初に始めるときは、チームで大規模なプログラムを書くのではなく、一人で小規模なプログラムを書きます。異なる人が書いたコンポーネントを個別に進化させるのに役立つカプセル化や名前空間は必要ありません。

そうなんですよね・・・ あの"Hello Java!"で沢山書いていた呪文が書かなくてよくなるとのことです。JDK21のプレビュー機能で導入され、Java23のプレビュー機能でこんなにコンパクトに・・・!!

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

java --enable-preview

これで実行すると本当に動くんですよね・・・
ちなみに、JEP477にはこんな記載がされていました。

修飾子staticは、言語のクラスとオブジェクトのモデルの一部です。初心者にとって、staticこれは不可解なだけでなく有害です。

23から新しく導入されたjava.io.IOクラスの導入により"System.out."を省略できるようになった点もコンパクトな実装を演出しています!!
https://cr.openjdk.org/~prappo/8305457/java.base/java/io/IO.html

初心者は、「System.out.println」という謎めいた呪文にさらに混乱し、なぜ単純な関数呼び出しでは十分ではないのかと疑問に思うかもしれません。また、プログラムの初週から、基本的な機能を使用するために基本的なユーティリティクラスをインポートする方法を学ばざるを得なくなり、なぜそれらが自動的に提供されないのかと不思議に思うかもしれません。

確かに・・・ 最初はとりあえず呪文とだけ教わってきたけど、まさか公式がここまで辛辣とは😂笑

JEP 455: Primitive Types in Patterns, instanceof, and switch (Preview)

https://openjdk.org/jeps/455

今回のJava23ではこのswitch式にプリミティブ型が使えるようになり、
JEP 455によって、instanceofは以下をサポートされることになったようです。
1: 原始型のチェック
• 変数が特定のプリミティブ型かどうかを確認できる。
2: 型キャストの簡略化
• 条件を満たす場合、自動的にキャストされる。
公式ドキュメントを訳すとこんな文言がありました!!

プリミティブ型に関連する複数の制限は、パターンマッチング、instanceof、およびswitchを使用する際に摩擦を生じさせます。これらの制限を排除することにより、Java言語はより一貫性があり、表現力豊かになるでしょう。

なので・・・instanceofの後にキャストを行なっていたのが、今回のプレビュー機能で型判定とキャストが組み合わさったってことですね😳!!

//  Object型からInteger型に自動キャストされる
Object value = 42; // ここの値を変えて動かしてみる
String result = switch (value) {
    case int i    -> "Integer型: " + i;
    case double d -> "Double型: " + d;
    case long l   -> "Long型: " + l;
    default -> "上記に該当しない型です";
};
println(result);

よかったら冒頭のリンク(playground)でスグに動かせるので試してみてください!!

Java14からはswitch式になったため、break文が不要になっていました。
今年のほとんどはJava8で実装してたのも相まってか、あまりswitch文も使ってこなかったのですが
breakのデフォルトになって、ここまでコンパクトになり、全ての型で使えるようになったのであれば是非使ってみたいな・・・!!って思いました😂

ちなみに、Java8はswitch式すら導入されていないので差分比較用に実装するとこんな感じかと思われます🤔 
Java23のプレビュー機能で実装と比較すると倍近くなりました笑

Object value = 42; // ここの値を変えて動かしてみる
String result = "";

if (value instanceof Integer) {
    int i = (Integer) value;
    result = "Integer型: " + i;
} else if (value instanceof Double) {
    double d = (Double) value;
    result = "Double型: " + d;
} else if (value instanceof Long) {
    long l = (Long) value;
    result = "Long型: " + l;
} else {
    result = "上記に該当しない型です";
}

System.out.println(result);

最後に

今、開発しているアプリケーションもやっとバージョンアップしてJava21になったのでモダンなJavaをフル活用して実装していけるように、
もっと色々な情報をキャッチアップして動かしみようと思います!!
ここまでお付き合いいただきありがとうございました🙇

ドキュメント/参考記事

【公式】
https://blogs.oracle.com/oracle4engineer/post/the-arrival-of-java-23-ja
【参考記事】
https://qiita.com/nowokay/items/7650b959fd4b0be54751#455-primitive-types-in-patterns-instanceof-and-switch-preview

Discussion