SHOEISHA iD

※旧SEメンバーシップ会員の方は、同じ登録情報(メールアドレス&パスワード)でログインいただけます

CodeZine編集部では、現場で活躍するデベロッパーをスターにするためのカンファレンス「Developers Summit」や、エンジニアの生きざまをブーストするためのイベント「Developers Boost」など、さまざまなカンファレンスを企画・運営しています。

【最新Javaアップデート解説】変更点と過去バージョンからのおさらい

「Java19」は何が新しいのか? 注目すべき新機能とJava17以降の変更点を解説

Java19での新しいAPI、変更点とJava17からのおさらい 第1回


  • X ポスト
  • このエントリーをはてなブックマークに追加

Switchでのパターンマッチ

 switch文を用いた条件分岐の拡張は、Java17までもプレビュー機能などでさまざまな拡張が行われてきました。例えば、Java17のプレビュー機能版ではリスト8のようなコードが記述できるようになりました。

[リスト8]Java17(プレビュー機能版)でのSwitchでのパターンマッチコード(src/main/java/src/jp/enbind/Jep427.javaの抜粋)
protected void switchSample17(Object value){
    if(value == null){
       return;
    }
    switch (value){
        case Integer i :
            if(i < 0) {
                System.out.println("less than 0");
            }
            else{
                System.out.println("more than 0");
            }
            break;
        default:
           break;
    }
}

 これだけでも、既存のJavaのコードに比べると簡素にコードが記述できるようになっていますが、Java19ではリスト9のように書き換えることが可能です。これにより、比較となる対象とその該当処理がよりわかりやすく記述することが可能です。

[リスト9]Java19(プレビュー機能版)でのSwitchでのパターンマッチコード(src/main/java/src/jp/enbind/Jep427.javaの抜粋)
protected void switchSample19(Object value){
    switch (value){
        // (1) case に nullを指定可能
        case null :
            System.out.println("is null");
            break;
        // (2) when による条件が指定可能
        case Integer i when i < 0:
            System.out.println("less than 0");
            break;
        case Integer i when i >= 0 :
            System.out.println("more than 0");
            break;
        default:
            break;
    }
}

 (1)のようにnullも含めることができるようになりました。そして、今まではif文で分岐させていたような条件も(2)のようにwhenを使った表現が可能です。この記述方法は、リスト10のようにswitch文ではなく、switch式でも同様に記述が可能です。

[リスト10]Java19(プレビュー機能版)でのSwitch式でのパターンマッチコード(src/main/java/src/jp/enbind/Jep427.javaの抜粋)
return switch (value){
    case null -> 0;
    case Integer i when i < 0 -> 1;
    case Integer i when i >= 0 -> 2;
    default -> -1;
};

仮想スレッド

 軽量版のスレッドが選択できるようになりました。これまでJavaでスレッドを作ると、JVMで決められたネイティブでのスレッドになります。そのため、スレッドを作るだけでも比較的負荷が高い処理になります。そのため、大量のスレッドを扱う場合にはスレッドプールなどのようにその負荷を軽減する方法などがとられてきました。

 しかし、C10K問題に向き合わなければならない場合など、どうしてもその問題から避けられないケースもあり、Java側の対応だけではなくOS側でも調整が必要になるケースがありました。

 今回では、そのような問題にも対応できる仮想スレッドが作成できるようになりました。この仮想スレッドは実際のOS上のスレッドではなく、JVM内で関係するスレッドです。これにより、軽量で大量のスレッド処理が行いやすくなりました。リスト11は仮想スレッドを作成する場合の簡単な実装例です。

[リスト11]仮想スレッドの作成方法(src/main/java/src/jp/enbind/Jep425.javaの抜粋)
// (1) 仮想スレッド用のFactoryクラスを作成
ThreadFactory factory = Thread.ofVirtual().factory();

// (2) 従来のスレッド用のFactoryクラスの場合
//ThreadFactory factory = Thread.ofPlatform().factory();

// (3) スレッドを作成する
Thread t = factory.newThread(new Runnable() {
    @Override
    public void run() {
        System.out.println("new thread");
    }
});
t.start();

 (1)で仮想スレッドを作成するためのFactoryクラスを作成します。既存のスレッド用のAPIでもThreadFactoryを引数にもつメソッドが追加されています。従来のスレッドを作成する場合には(2)のようにThreadFactoryを作成します。また、ThreadFactoryが引数にない従来のメソッドを利用した場合でも従来のスレッドが作成されます。あとは、(3)のようにスレッドを作成し、実行できます。

 実際の動作の影響は、このような簡単な処理では違いがよくわかりません。しかし、リスト12のようなコードを実行した場合、その違いが生じます。

[リスト12]Executorsを用いたスレッドの実行(src/main/java/src/jp/enbind/Jep425.javaの抜粋)
// (1) 仮想スレッドを用いた場合の実行
try(
   var executor = Executors.newVirtualThreadPerTaskExecutor();
){
    // (2) 大量のスレッドを実行する
    IntStream.range(0,10000).forEach(i ->{
       executor.submit(() ->{
           System.out.println("i is " + i);
           Thread.sleep(5000);
           return i;
       });
    });
}

// (3) 通常のスレッドを用いた場合の実行
ThreadFactory factory = Thread.ofPlatform().factory();
try(
    var executor = Executors.newThreadPerTaskExecutor(factory);
){
    IntStream.range(0,1000).forEach(i ->{
     executor.submit(() ->{
         System.out.println("i is " + i);
        Thread.sleep(5000);
         return i;
       });
    });
}

 (1)は仮想スレッドを用いた場合のコードです。(2)で5秒ほどかかる処理を同時に10000個実行しています。同様の処理を通常のスレッドを用いて行ったものが、(3)のコードです。こちらは、筆者の環境では実行が終了できず、エラーになってしまいました。

 もちろん、実行する環境によって上限は違いますが、このようにリソースを大量に消費するコードの場合には、仮想スレッドと通常のスレッドの違いがわかると思います。

Finalizeメソッドの無効オプションの追加

 Java9からすでにfinalizeメソッドを利用したコードを記述することは推奨されていませんが、まだ、利用されているコードがあります。ただし、今後のバージョンではデフォルトで無効や削除が予定されています。

 そこで、実行時に--finalization=disabledを指定することで、ファイナライザ機能を無効にすることができます。このオプションをつけて問題なく動くようにすることで、今後のJavaのバージョンアップの際にも思わぬ不具合をおこすようなことがないように準備できます。

まとめ

 Java18とJava19はJava17までの変更に比べ、どちらかと言えば、これまでの機能や環境の整備といえる変更と筆者は感じました。次のLTSバージョンでも大きく変わらず同様の流れになると思います。Javaを中心に利用している筆者としては少々寂しくもありますが、より成熟した言語として利用されているということでもあり、大きな変更がないことはメリットでもあります。

 一方で、クラウド環境との親和性などのようなJVM周りについてはまだまだ、発展する余地があります。今後はそのような機能が拡充され、Javaがより発展することを期待したいと思います。

この記事は参考になりましたか?

  • X ポスト
  • このエントリーをはてなブックマークに追加
【最新Javaアップデート解説】変更点と過去バージョンからのおさらい連載記事一覧

もっと読む

この記事の著者

WINGSプロジェクト 小林 昌弘(コバヤシ マサヒロ)

WINGSプロジェクトについて>有限会社 WINGSプロジェクトが運営する、テクニカル執筆コミュニティ(代表 山田祥寛...

※プロフィールは、執筆時点、または直近の記事の寄稿時点での内容です

山田 祥寛(ヤマダ ヨシヒロ)

静岡県榛原町生まれ。一橋大学経済学部卒業後、NECにてシステム企画業務に携わるが、2003年4月に念願かなってフリーライターに転身。Microsoft MVP for Visual Studio and Development Technologies。執筆コミュニティ「WINGSプロジェクト」代表。主な著書に「独習シリーズ(Java・C#・Python・PHP・Ruby・JSP&サーブレットなど)」「速習シリーズ(ASP.NET Core・Vue.js・React・TypeScript・ECMAScript、Laravelなど)」「改訂3版JavaScript本格入門」「これからはじめるReact実践入門」「はじめてのAndroidアプリ開発 Kotlin編 」他、著書多数

※プロフィールは、執筆時点、または直近の記事の寄稿時点での内容です

この記事は参考になりましたか?

この記事をシェア

  • X ポスト
  • このエントリーをはてなブックマークに追加
CodeZine(コードジン)
https://codezine.jp/article/detail/16512 2022/10/18 11:18

おすすめ

アクセスランキング

アクセスランキング

イベント

CodeZine編集部では、現場で活躍するデベロッパーをスターにするためのカンファレンス「Developers Summit」や、エンジニアの生きざまをブーストするためのイベント「Developers Boost」など、さまざまなカンファレンスを企画・運営しています。

新規会員登録無料のご案内

  • ・全ての過去記事が閲覧できます
  • ・会員限定メルマガを受信できます

メールバックナンバー

アクセスランキング

アクセスランキング