$30 off During Our Annual Pro Sale. View Details »

Java16新機能-言語とAPIを中心に- / Java 16 new features - about lang and API -

Java16新機能-言語とAPIを中心に- / Java 16 new features - about lang and API -

2021/3/16に開催されたJJUG night seminarでの登壇資料です
https://jjug.doorkeeper.jp/events/119184

Naoki Kishida

March 16, 2021
Tweet

More Decks by Naoki Kishida

Other Decks in Programming

Transcript

  1. Java 16新機能
    言語とAPIを中心に
    あとAlpine Linux
    JJUG Night Seminar 2021/3/16
    LINE Fukuoka きしだ なおき

    View Slide

  2. Java 16
    • 2021/3/16リリース
    • non-LTS
    • 次は17(Sept.2021)
    • 17個のJEP
    http://openjdk.java.net/projects/jdk/16/

    View Slide

  3. Java 16
    • 2021/3/16リリース
    • non-LTS
    • 次は17(Sept.2021)
    • 17個のJEP
    http://openjdk.java.net/projects/jdk/16/
    LTS(Long Term Support)
    長期サポート
    6バージョンごとにLTSが設定されて長期間の
    サポートが行われる。
    現在のLTSは11で、次回は17。
    15はLTSではないので16が出ればバグ修正など
    は行われなくなる。

    View Slide

  4. Java 16
    • 2021/3/16リリース
    • non-LTS
    • 次は17(Sept.2021)
    • 17個のJEP
    http://openjdk.java.net/projects/jdk/16/

    View Slide

  5. Java 16
    • 2021/3/16リリース
    • non-LTS
    • 次は17(Sept.2021)
    • 17個のJEP
    http://openjdk.java.net/projects/jdk/16/
    JEP(JDK Enhancement Proposal)
    機能改善のまとめ
    主な仕様変更はJEPとしてまとめられている

    View Slide

  6. Java 16
    • 2021/3/16リリース
    • non-LTS
    • 次は17(Sept.2021)
    • 17個のJEP
    • 更新4個
    • うち3個が正式化
    http://openjdk.java.net/projects/jdk/16/
    正式化
    正式化
    更新
    更新
    正式化

    View Slide

  7. Java 16
    • 2021/3/16リリース
    • non-LTS
    • 次は17(Sept.2021)
    • 17個のJEP
    • 更新4個
    • うち3個が正式化
    http://openjdk.java.net/projects/jdk/16/
    正式化
    正式化
    更新
    更新
    正式化
    Javaの試用機能
    大きな新機能について試用版として導入することで
    フィードバックを得やすくしてよりよい機能を提供
    できるようにする
    • 言語機能:Preview
    • API:Incubator
    • JVM機能:Experimental
    17LTSにはPreviewは残さない意向に見える

    View Slide

  8. JEP
    • 言語仕様
    • Pattern Matching for instanceof
    • Records
    • Sealed Classes(Second Preview)
    • Warnings for Value-Based Classes
    • API
    • Foreign Memory Access API
    (Third Incubator)
    • Vector API(Incubator)
    • Foreign Linker API(Incubator)
    • Unix-Domain Socket Channels
    • Tool
    • Packaging Tool
    • JVM
    • ZGC: Concurrent Thread-Stack
    Processing
    • Elastic Metaspace
    • Strongly Encapsulate JDK
    Internals by Default
    • OpenJDK
    • Migrate from Mercurial to Git
    • Migrate to GitHub
    • Enable C++14 Language Features
    • Alpine Linux Port
    • Windows/AArch64 Port

    View Slide

  9. JEP
    • 言語仕様
    • Pattern Matching for instanceof
    • Records
    • Sealed Classes(Second Preview)
    • Warnings for Value-Based Classes
    • API
    • Foreign Memory Access API
    (Third Incubator)
    • Vector API(Incubator)
    • Foreign Linker API(Incubator)
    • Unix-Domain Socket Channels
    • Tool
    • Packaging Tool
    • JVM
    • ZGC: Concurrent Thread-Stack
    Processing
    • Elastic Metaspace
    • Strongly Encapsulate JDK
    Internals by Default
    • OpenJDK
    • Migrate from Mercurial to Git
    • Migrate to GitHub
    • Enable C++14 Language Features
    • Alpine Linux Port
    • Windows/AArch64 Port

    View Slide

  10. ダウンロードサイト
    • Oracle OpenJDK
    • http://jdk.java.net/16/
    • AdoptOpenJDK
    • https://adoptopenjdk.net/?variant=openjdk16&jvmVariant=hotspot
    • Amazon Corretto
    • https://github.com/corretto/corretto-jdk/releases/tag/16.0.0.36.1
    • Azul Zulu Community
    • https://jp.azul.com/downloads/zulu-community/?version=java-16-
    ea&architecture=x86-64-bit&package=jdk
    • Liberica JDK
    • https://bell-sw.com/pages/java-16/
    • Oracle JDK
    • https://www.oracle.com/java/technologies/javase-jdk16-downloads.html

    View Slide

  11. 言語仕様
    • Pattern Matching for instanceof(Standard)
    • Records(Standard)
    • Sealed Classes(Second Preview)
    • Warnings for Value-Based Classes

    View Slide

  12. Pattern Matching for instanceof(Standard)
    • Kotlinのスマートキャストのような機能
    Object o = "test";
    if (o instanceof String s) {
    System.out.println(s.length());
    }
    Object o = "test";
    if (o instanceof String) {
    String s = (String) o;
    System.out.println(s.length());
    }

    View Slide

  13. Records(Standard)
    • データをやりとりするための型
    • イミュータブル(値が変更できない)
    • 名前付きタプル
    • Case class(Scala) やData class(Kotlin), @Value(Lombok)

    View Slide

  14. Recordの定義
    public record Rec(String name, int count) {}
    public final class Rec extends Record {
    private final String name;
    private final int count;
    Rec(String name, int count) {
    this.name = name;
    this.count = count;
    }
    String name() { return name; }
    String count() { return count; }
    // toString, equals, hashCode
    }
    recordで宣言

    View Slide

  15. Recordの定義
    public record Rec(String name, int count) {}
    public final class Rec extends Record {
    private final String name;
    private final int count;
    Rec(String name, int count) {
    this.name = name;
    this.count = count;
    }
    String name() { return name; }
    String count() { return count; }
    // toString, equals, hashCode
    }
    要素(コンポーネント)を定義

    View Slide

  16. Recordの定義
    public record Rec(String name, int count) {}
    public final class Rec extends Record {
    private final String name;
    private final int count;
    Rec(String name, int count) {
    this.name = name;
    this.count = count;
    }
    String name() { return name; }
    String count() { return count; }
    // toString, equals, hashCode
    }
    中かっこが必要
    追加のメソッドなどの定義も可

    View Slide

  17. Recordの定義
    public record Rec(String name, int count) {}
    public final class Rec extends Record {
    private final String name;
    private final int count;
    Rec(String name, int count) {
    this.name = name;
    this.count = count;
    }
    String name() { return name; }
    String count() { return count; }
    // toString, equals, hashCode
    }
    暗黙にfinal

    View Slide

  18. Recordの定義
    public record Rec(String name, int count) {}
    public final class Rec extends Record {
    private final String name;
    private final int count;
    Rec(String name, int count) {
    this.name = name;
    this.count = count;
    }
    String name() { return name; }
    String count() { return count; }
    // toString, equals, hashCode
    }
    java.lang.Recordを継承

    View Slide

  19. Recordの定義
    public record Rec(String name, int count) {}
    public final class Rec extends Record {
    private final String name;
    private final int count;
    Rec(String name, int count) {
    this.name = name;
    this.count = count;
    }
    String name() { return name; }
    String count() { return count; }
    // toString, equals, hashCode
    }
    コンポーネントに
    対応するフィールド
    private final

    View Slide

  20. Recordの定義
    public record Rec(String name, int count) {}
    public final class Rec extends Record {
    private final String name;
    private final int count;
    Rec(String name, int count) {
    this.name = name;
    this.count = count;
    }
    String name() { return name; }
    String count() { return count; }
    // toString, equals, hashCode
    }
    コンストラクタが定義される

    View Slide

  21. Recordの定義
    public record Rec(String name, int count) {}
    public final class Rec extends Record {
    private final String name;
    private final int count;
    Rec(String name, int count) {
    this.name = name;
    this.count = count;
    }
    String name() { return name; }
    String count() { return count; }
    // toString, equals, hashCode
    }
    コンポーネントと同名の
    アクセスメソッド
    getterではない

    View Slide

  22. Recordの定義
    public record Rec(String name, int count) {}
    public final class Rec extends Record {
    private final String name;
    private final int count;
    Rec(String name, int count) {
    this.name = name;
    this.count = count;
    }
    String name() { return name; }
    String count() { return count; }
    // toString, equals, hashCode
    }
    オブジェクトの基本メソッドも
    実装される

    View Slide

  23. Recordの利用
    • 利用時は普通のクラスと同様
    Rec r = new Rec("Java", 15);

    View Slide

  24. カノニカルコンストラクタ
    • コンストラクタの定義では、引数にコンポーネントをその型で
    その順番で、そしてそれだけを書く必要がある
    • コンポーネントに対応する内部フィールドを必ず初期化しない
    といけない
    • カノニカル(正規)コンストラクタ

    View Slide

  25. カノニカル(正規)コンストラクタ
    • コンポーネントと同じパラメータとフィールド初期化が必要
    record Rec(String name, int count) {
    Rec(String name, int count) {
    this.name = name;
    this.count = Math.max(count, 0);
    }
    }
    コンポーネントと同じ
    パラメータが必要

    View Slide

  26. カノニカル(正規)コンストラクタ
    • コンポーネントと同じパラメータとフィールド初期化が必要
    record Rec(String name, int count) {
    Rec(String name, int count) {
    this.name = name;
    this.count = Math.max(count, 0);
    }
    }
    フィールド初期化が必須

    View Slide

  27. コンパクトコンストラクタ
    • 必ず書かないといけないものは省略していいのでは?
    record Rec(String name, int count) {
    Rec {
    count = Math.max(count, 0);
    }
    }
    パラメータを省略

    View Slide

  28. コンパクトコンストラクタ
    • 必ず書かないといけないものは省略していいのでは?
    record Rec(String name, int count) {
    Rec {
    count = Math.max(count, 0);
    }
    }
    フィールドを初期化してはいけない

    View Slide

  29. Sealed Classes(2nd Preview)
    • 継承できるクラスを限定する
    • shield(盾) classではなくてsealed(密閉された) class
    public abstract sealed class Shape
    permits Circle, Rectangle, Square {...}

    View Slide

  30. Preview機能
    • 言語機能の試用版
    • 基本的にpreview, second previewの2回のpreviewを経て正式
    化する
    • 正式化までに3バージョン必要
    • 明確な決まりがあるわけではない
    • javacやjavaコマンドなどで`--enable-preview`が必要
    • `-source`でのバージョン指定も必要
    jshell> sealed class Hoge{}
    | エラー:
    | シール・クラスはプレビュー機能であり、デフォルトで無効になっています。
    | (シール・クラスを有効にするには--enable-previewを使用します)
    | sealed class Hoge{}
    | ^

    View Slide

  31. ( ´∀`)<シールドクラス
    • 公式にはシール・クラス?
    jshell> sealed class Hoge{}
    | エラー:
    | シール・クラスはプレビュー機能であり、デフォルトで無効になっています。
    | (シール・クラスを有効にするには--enable-previewを使用します)
    | sealed class Hoge{}
    | ^

    View Slide

  32. 現状では使い道なし
    • 本当は次のように書けるといい
    • Pattern matching for switchなどが来れば便利に(Java 18かな)
    String getName(Shape s) {
    if (s instanceof Circle) {
    return "円";
    } else if (s instanceof Rectangle) {
    return "四角";
    } else if (s instanceof Square) {
    return "正方形";
    }
    }

    View Slide

  33. Sealed Classesの階層
    • Sealed Classを継承する場合、sealed・final・non-sealedの
    いずれかが必要
    • recordは暗黙的にfinal Hoge
    Foo Bar
    Baz
    sealed
    要 sealed
    要 final or non-sealed
    要 final or non-sealed
    MyBaz Bazがnon-sealedであれば
    継承できる。sealされない
    sealed class Hoge
    permits Foo, Bar {}
    final class Foo extends Hoge {}
    sealed class Bar extends Hoge
    permits Baz {}
    non-sealed class Baz extends Bar {}
    class MyBaz extends Baz {}

    View Slide

  34. non-sealed
    • ハイフン入りキーワード!
    • 実際はキーワードではない
    • switch式のときにbreak-withが検討されていた
    • package-privateなども可能

    View Slide

  35. API
    • Vector API(Incubator)
    • Foreign Memory Access API(3rd Incubator)
    • Foreign Linker API(Incubator)
    • Unix-Domain Socket Channels

    View Slide

  36. Vector API(Incubator)
    • AVX命令のような、複数のデータに対する計算を同時に行う
    命令(SIMD - Single Instruction Multiple Data)をJavaから利用
    import jdk.incubator.vector.*;
    static final VectorSpecies SPECIES = FloatVector.SPECIES_256;
    void vectorComputation(float[] a, float[] b, float[] c) {
    // SPECIES.length() = 256bit / 32bit -> 8
    for (int i = 0; i < a.length; i += SPECIES.length()) {
    // 端数がマスクされる
    // a.lengthが11でiが8のとき最初の3つしか要素がないので [TTT.....]
    VectorMask m = SPECIES.indexInRange(i, a.length);
    FloatVector va = FloatVector.fromArray(SPECIES, a, i, m);
    FloatVector vb = FloatVector.fromArray(SPECIES, b, i, m);
    FloatVector vc = va.mul(va).
    add(vb.mul(vb)).
    neg();
    vc.intoArray(c, i, m);
    }
    }

    View Slide

  37. どんなハードウェアで使える?
    • IntelハイエンドだとAVX512に対応
    • double(64bit) x 8
    • なんだけど、i7 7820Xでdouble x 4までしか使えず
    • ほかのi7やi5などは256bit
    • M1は128bit
    • double x 2
    • float x 4

    View Slide

  38. • SmallPT
    レイトレやってみる
    https://github.com/kishida/smallpt4j/blob/vector/src/main/java/naoki/smallpt/SmallPT.java
    public class SmallPT {
    private static final int SAMPLES_DEFAULT = 40;
    private static final VectorSpecies SPECIES = DoubleVector.SPECIES_256;
    static DoubleVector fromValues(double x, double y, double z) {
    return DoubleVector.fromArray(SPECIES, new double[]{x, y, z, 0}, 0);
    }
    static DoubleVector normalize(DoubleVector v) {
    double dist = sqrt(v.mul(v).reduceLanes(VectorOperators.ADD));
    return v.div(dist);
    }
    static double dot(DoubleVector v, DoubleVector b) {
    return v.mul(b).reduceLanes(VectorOperators.ADD);
    } // cross:
    static VectorShuffle yzx = VectorShuffle.fromValues(SPECIES, 1, 2, 0, 3);
    static DoubleVector mod(DoubleVector v, DoubleVector b) {
    // return v.rearrange(yzx).mul(b.rearrange(zxy)).sub(v.rearrange(zxy).mul(b.rearrange(yzx)));
    return v.mul(b.rearrange(yzx)).sub(v.rearrange(yzx).mul(b)).rearrange(yzx);
    }

    View Slide

  39. 結果
    • Vector版 9.7秒
    • 通常版 6.3秒
    • おそい・・・
    • JITがきいてない
    • 複雑な処理ではまだパフォーマンスが出なさそう

    View Slide

  40. Foreign memory Access API(3rd incubator)
    • 大量データを処理するために、GCで管理されないメモリを
    確保する
    • 標準ではないUnsafeを使っていたものを標準APIで実現する
    • --add-modules jdk.incubator.foreign が必要
    import jdk.incubator.foreign.*;
    try (MemorySegment segment = MemorySegment.allo
    cateNative(100)) {
    for (int i = 0 ; i < 25 ; i++) {
    MemoryAccess.setIntAtOffset(i * 4, i);
    }
    }

    View Slide

  41. One more thing!

    View Slide

  42. Stream.toList()

    View Slide

  43. Stream.toList()
    • collector(Collectors.toUnmodifiableList())と書く必要
    がなくなった!
    • 変更不可のリストなのでCollectors.toList()を置き換える
    ときは注意
    C:¥Users¥naoki>java¥jdk¥jdk-16¥bin¥jshell
    | JShellへようこそ -- バージョン16
    | 概要については、次を入力してください: /help intro
    jshell> Stream.of("a","b","c").toList()
    $1 ==> [a, b, c]
    jshell> /var $1
    | List $1 = [a, b, c]
    jshell> $1.getClass()
    $2 ==> class java.util.ImmutableCollections$ListN

    View Slide

  44. OpenJDK
    • Windows/AArch64 Port
    • Alpine Linux Port

    View Slide

  45. ARM Mac対応は17っぽい
    • まだ一覧には のってない

    View Slide

  46. Alpine Linuxで最小Docker Imageを作る

    View Slide

  47. Alpine Linux
    • musl
    • c標準ライブラリ
    • glibc互換
    • コンパクトに整理されている
    • ヘッダが人間にも読める
    • glibcは#ifdefたくさんで読みにくい
    • busybox
    • すべてのコマンドがbusyboxにsymbolic link
    • apk
    • パッケージ管理

    View Slide

  48. 16にはまだAlpineバイナリがない・・・
    • JDK 16 RC
    http://jdk.java.net/16/

    View Slide

  49. では自分でビルドだ
    • bash configure
    make
    • ソースはGitHub
    https://github.com/openjdk/jdk/tree/jdk-16+36

    View Slide

  50. ビルドエラー (T^T)
    • allocaの戻り値を使っていないという警告が

    View Slide

  51. パッチ
    • ダミー変数に割り当てる
    672c672
    < alloca(((pid ^ counter++) & 7) * 128);
    ---
    > int* dummy = (int*)alloca(((pid ^ counter++) & 7) * 128);

    View Slide

  52. 結構大きい
    • Spring Boot+Spring MVCのHello Worldを動かす
    • 961MB

    View Slide

  53. jlinkで実行環境を最適化
    • 必要なモジュールだけを持つJava実行環境をつくる
    • jdepsで必要なモジュールを確認する
    • Springのようなfat-jarでは一度展開してライブラリjarを取り出して
    おく必要がある
    > jlink --compress 2 --strip-debug --no-header-files --no-man-pages --output
    /src/jre --add-modules
    java.base,java.desktop,java.instrument,java.management.rmi,java.naming,java.pref
    s,java.scripting,java.security.jgss,java.sql,jdk.httpserver,jdk.jfr,jdk.unsuppor
    ted

    View Slide

  54. 77MB
    • 77MBのイメージができた

    View Slide

  55. 参考
    • UbuntuやJibを使ってみる

    View Slide

  56. Shenandoahとかいらなくない?
    • 使わない機能がたくさんある
    • Javaには6つのGCがある
    • 1つしか使わない
    • 削ってみる

    View Slide

  57. --disable-jvm-feature
    • 使わないものを無効にしてみる
    bash configure --disable-jvm-feature-aot --disable-jvm-feature-graal --disable-
    jvm-feature-parallelgc --disable-jvm-feature-shenandoahgc --disable-jvm-feature-
    zgc --disable-jvm-feature-epsilongc --disable-jvm-feature-jvmci --disable-jvm-
    feature-jni-check --disable-jvm-feature-dtrace

    View Slide

  58. 結果:そんな小さくない
    • 74MB

    View Slide

  59. もっと削ってみる
    • JITいらんくない?
    • Serial GCでよくない?
    • 管理しねーし
    bash configure --disable-jvm-feature-aot --disable-jvm-feature-graal --
    disable-jvm-feature-parallelgc --disable-jvm-feature-shenandoahgc --
    disable-jvm-feature-zgc --disable-jvm-feature-epsilongc --disable-jvm-
    feature-jvmci --disable-jvm-feature-jni-check --disable-jvm-feature-dtrace
    --disable-jvm-feature-cds --disable-jvm-feature-compiler1 --disable-jvm-
    feature-compiler2 --disable-jvm-feature-jvmti --disable-jvm-feature-jfr --
    disable-jvm-feature-management --disable-jvm-feature-g1gc --disable-jvm-
    feature-services --disable-jvm-feature-nmt --disable-jvm-feature-vm-structs
    --disable-jvm-feature-link-time-opt

    View Slide

  60. 60MB!
    • だいぶ小さくなった

    View Slide

  61. 結果
    • すごく小さいです!
    0
    50
    100
    150
    200
    250
    Alpine最小 Alpineほどほど Alpine Ubuntu Jib

    View Slide

  62. うごいた!
    • 動きます
    • でも遅い
    • 2秒→9秒

    View Slide

  63. まとめ
    • recordとtoList便利そう

    View Slide