Quantcast
Channel: プログラミング
Viewing all articles
Browse latest Browse all 7851

【事前調査】JEP 455調査したさいのメモ - エンターテイメント!!

$
0
0

きっかけ

Java23のリリースが近づいてきたので、事前調査。
Javaのリリース時期が、俺の誕生日と近いから、否が応でも思い出すんだよなぁ。。。

前提

  • 環境準備は、sdkman使う。利用方法は明記しない。
  • 2024/09/01時点での内容。

環境準備

sdkmanを使っているので、それで準備

$ sdk install java 23.ea.29-open

インストールされているか確認する。
現場猫ばりの確認をしないと、後続の作業がムダになる可能性もあるから、慎重に。

$ javac -version
javac 23-ea
$ java --version
openjdk 23-ea 2024-09-17
OpenJDK Runtime Environment (build 23-ea+29-2309)
OpenJDK 64-Bit Server VM (build 23-ea+29-2309, mixed mode, sharing)

これで環境準備完了

調査

内容

Google翻訳で翻訳かけてみたら以下になった。

すべてのパターン コンテキストでプリミティブ型パターンを許可することでパターン マッチングを強化し、すべてのプリミティブ型で動作するように拡張します。

ど、どういうことだってばよ。。。?
おそらく、パターンマッチングで何かしら動作するようになったくらいの認識でいる。
とりあえず、サンプルコード試してみないと俺の頭では分からなそう。。。

サンプル実装 プリミティブ型パターンのサポートによるSwitch式

public class Jep455 {

  public static void main(String[] args) {

    int status = Integer.parseInt(args[0]);

    String msg = switch (status) {
        case 0 -> "okay";     // 1
        case 1 -> "warning";  // 2
        case 2 -> "error";    // 3
        case int i -> "unknown status: " + i; // 4
    };

    System.out.println(msg);
  }

}

やっていることの説明としては、引数で受け取った値をint型のstatusという変数に格納して、そのステータスによってメッセージを出し分けている。
注目してほしいのは、コメントの4の行。
指定にintが使える。
Java22までは、クラスか配列しか指定できなかったはずだが、Java23のプレビューでプリミティブな型を指定できるようになっている。
何をしているかというと、0~2以外の数値が"unknown status: x"に落ちるようになっている。

認識間違ってないか不安になったので、Java22に切り替えてコンパイルしようとすると、下記のエラーになった。

$ javac Jep455.java
Jep455.java:11: エラー: 予期しない型
        case int i -> "unknown status: " + i; // 4
             ^
  期待値: クラスまたは配列
  検出値:    int
エラー1個
}

やはり、Java23で入ったやつだ。誤読はしてなさそう。

気を取り直して、Java23に戻して、コンパイル後、実際に動かしてみる。

$ javac --enable-preview --release 23 Jep455.java
$ java --enable-preview Jep455 0
okay

$ java --enable-preview Jep455 1
warning

$ java --enable-preview Jep455 2
error

$ java --enable-preview Jep455 3
unknown status: 3

ちゃんと動いてやがる。。。

本当に大丈夫なのか疑問に思ったので、intの最大と最小値で試してみる。

$ java --enable-preview Jep455 -2147483648
unknown status: -2147483648

$ java --enable-preview Jep455 2147483647
unknown status: 2147483647

ちゃんと想定通りのところに落ちてる。

疑問その1 型の指定がズレているとどうなるのか?

public class Jep455 {

  public static void main(String[] args) {
    long status = Long.parseLong(args[0]);
    String msg = switch (status) {
        case 0 -> "okay";     // 1
        case 1 -> "warning";  // 2
        case 2 -> "error";    // 3
        case int i -> "unknown status: " + i; // 4
    };

    System.out.println(msg);
  }

}

longを渡すように変更して、いざコンパイル

$ javac --enable-preview --release 23 Jep455.java
Jep455.java:4: エラー: シンボルを見つけられません
    long status = Long.pareLong(args[0]);
                      ^
  シンボル:   メソッド pareLong(String)
  場所: クラス Long
Jep455.java:6: エラー: タイプintの定数ラベルがswitchセレクタ・タイプlongと互換性がありません
        case 0 -> "okay";     // 1
             ^
Jep455.java:7: エラー: タイプintの定数ラベルがswitchセレクタ・タイプlongと互換性がありません
        case 1 -> "warning";  // 2
             ^
Jep455.java:8: エラー: タイプintの定数ラベルがswitchセレクタ・タイプlongと互換性がありません
        case 2 -> "error";    // 3

caseで指定しているのは、全部intだから、型違いで怒られるわけか。。。
case式のところをLong型変えればいけるのだろうか?個人的予想は、"case int i"で怒られる気がする。

修正したソース

public class Jep455 {

  public static void main(String[] args) {
    long status = Long.parseLong(args[0]);
    String msg = switch (status) {
        case 0L -> "okay";     // 1
        case 1L -> "warning";  // 2
        case 2L -> "error";    // 3
        case int i -> "unknown status: " + i; // 4
    };

    System.out.println(msg);
  }
}

再度、コンパイルしてみる。

$ javac --enable-preview --release 23 Jep455.java 
Jep455.java:5: エラー: switch式がすべての可能な入力値をカバーしていません
    String msg = switch (status) {

そこで怒られるのね。。。
あれか、defaultがない場合のエラーに落ちてる感じだろうか?
switch式は網羅してないとダメなんだったかな?

疑問その2 型の安全性とは?

※最初から、こうしようと思った訳では無いが、意図せず確認できたので、章分け。

前回で、longの範囲をカバーできてなかったので、case式にlongを追加してみる。

public class Jep455 {

  public static void main(String[] args) {
    long status = Long.parseLong(args[0]);
    String msg = switch (status) {
        case 0L -> "okay";     // 1
        case 1L -> "warning";  // 2
        case 2L -> "error";    // 3
        case int i -> "unknown status: " + i; // 4
        case long j -> "unknown long status:" + j; // 5
    };

    System.out.println(msg);
  }

}

コンパイルして実行してみる。

$ javac --enable-preview --release 23 Jep455.java 

$ java --enable-preview Jep455 4
unknown status: 4

$ java --enable-preview Jep455 2147483648
unknown long status:2147483648

ありゃ、"4"を指定したときは、intのcaseに落ちてる。
これが、"変換の安全性"で言っているやつか?
情報の損失が発生しない場合、変換は正確に行われるらしいから、先に定義しているintのcase式に落ちているわけね。
逆に、intでは表現不可な値を渡した場合は、変換が正確に行えないから、longのcase式に落ちていると。

感想・雑記など

switch式の調査だけでお腹いっぱいになってしまった。。。
プリミティブな型(int/long/byte/short...etc)が使えるようになったというのは確認できた。
switchを多用する人間ではないのだが、switch書く人にとってはメリットでかいのだろうか?

調査したのはいいんだけど、なんか不安なんだよなぁ。。。
えらい人の解説とかも読まんと、なんか安心できない。

おそらく、リリース後に情報が大量に出てくるだろうから、そのタイミングで自分の知識がまちがってないか、復習しないと。。。

なんか、学習体力的なものが落ちている気がする。
他にもJEP`あるけど、調査する気力がなくなってしまった。
学習が継続しないんだよなぁ。
分かる人おる?
学生時代はそうでもなかったんだが。。。
他人の目がないと、徹底的に怠惰になるクセが付いているのかもしれない。

関連リンク

JDK 23


Viewing all articles
Browse latest Browse all 7851

Trending Articles