Javaの新機能を軽く / Breaf introduction of Java 14

Javaの新機能を軽く / Breaf introduction of Java 14

2020/5/22に開催されたJJUGイベントでの登壇資料です。

9e840766611f942c7c0a9ad6987a5d78?s=128

Naoki Kishida

May 22, 2020
Tweet

Transcript

  1. Java14新機能を軽く 2020/5/23 Java生誕25周年 記念イベント LINE Fukuoka きしだ なおき

  2. 自己紹介 • きしだ なおき • LINE Fukuoka • @kis •

    https://nowokay.hatenablog.com/
  3. タイトル画像について • ストックホルム宮殿 • カール14世ヨハン元国王の像 • 2020/2/2 JFokusで撮影 wikimediaより

  4. chiroitoによる再現

  5. Java 14がリリースされてますね • 3/17にリリース • 16 JEPs • 主な新機能はJEPとして まとめられている

    • non LTS • パッチはJava15が出るまで • 現在は14.0.1がリリース • 7月の14.0.2まで • 次のLTSは17(2021年9月)
  6. Java 14の機能 • 言語 • Records(preview) • Pattern Matching(preview) •

    Text Blocks(preview 2) • Switch Expression(standard) • GC • ZGC: supports Windows/Mac • G1:NUMA aware memory alloc • CMS: Removed • ParallelGC: Deprecate useless option (Parallel Young gen+Serial Old) • ライブラリ • Helpful NullPointerException • JFR event streaming • Foreign Memory Access(Incubator) • Non-volatile mapped byte buffer • ツール • Packaging Tool(Incubator) • Remove Pack200 • JDK • Deprecate Solaris/SPARC
  7. Java 14の機能 • 言語 • Records(preview) • Pattern Matching(preview) •

    Text Blocks(preview 2) • Switch Expression(standard) • GC • ZGC: supports Windows/Mac • G1:NUMA aware memory alloc • CMS: Removed • ParallelGC: Deprecate useless option (Parallel Young gen+Serial Old) • ライブラリ • Helpful NullPointerException • JFR event streaming • Foreign Memory Access(Incubator) • Non-volatile mapped byte buffer • ツール • Packaging Tool(Incubator) • Remove Pack200 • JDK • Deprecate Solaris/SPARC
  8. ところで試用機能について • 試用機能 • JDKリリースに含まれることで手軽に試せて、多くのフィードバックができる • Preview • 言語機能 •

    `--enable-preview` がjava / javac コマンドに必要 • 3段階で標準化 • preview: Records, Pattern Matching for instanceof • preview 2(小変更が入る): Text Blocks • standard(変更は入らない): Switch Expression • Incubator • ライブラリ • incubatorモジュールのインポートが必要 • Experimental • JVM機能(GC, JIT) • -XX:+UnlockExperimentalVMOptions • 正式化するときは‘Production’(standardではない)
  9. 言語機能 • Text Blocks(Preview2) • Switch expression(Standard) • Records(Preview) •

    Pattern matching for instanceof(Preview)
  10. 言語機能 • Text Blocks(Preview2) • Switch expression(Standard) • Records(Preview) •

    Pattern matching for instanceof(Preview)
  11. Text Blocks(Preview 2) • 複数行のテキスト • ダブルクオート3つで囲む • Raw Stringsとして12で導入されかけたけどバッククオートが

    もったいないとして取り下げ • Text BlocksとしてJava 13でPreviewとして入った。15で Standardになる予定(JEP 378) """ <head> <title>Java 14</title> </head> """
  12. ルール """ <head> <title>Java 14</title> </head> """ ダブルクオート3つは内容の文字列とは独立した行に 右端のスペースは無視される

  13. var s = """ <head> <title>Java 14</title> </head> """; var

    s = """ <head> <title>Java 14</title> </head> """; var s = """ <head> <title>Java 14</title> </head> """; インデント • 一番ひだりにあわせられる `<head>`の位置が基準 閉じ側の`"""`の位置が基準 `<head>`の位置が基準
  14. エスケープ • 14でのPreview2で入った • 改行のエスケープ(¥) • スペース文字(¥s) • 行末のスペースは無視される •

    行末にスペースが欲しいときは ‘¥s’を入れる var s = """ Lorem ipsum dolor ¥ sit amet consectetur ¥s """; var s = "Lorem ipsum dolor sit amet consectetur ";
  15. 言語機能 • Text Blocks(Preview2) • Switch expression(Standard) • Records(Preview) •

    Pattern matching for instanceof(Preview)
  16. Switch expression(Standard) • Switchがステートメントとしてだけではなく式として使える • 最初にJava 12でPreviewとして導入された • Java 13で少し変更が入りPreview

    2になりそのまま標準化 int numLetters = switch (day) { case MONDAY, FRIDAY, SUNDAY -> 6; case TUESDAY -> 7; case THURSDAY, SATURDAY -> 8; case WEDNESDAY -> 9; }
  17. 複数のcaseラベル • case句に複数のラベルを指定できるようになった switch (day) { case MONDAY: case FRIDAY:

    case SUNDAY: numLetters = 6; break; case TUESDAY: numLetters = 7; break; case THURSDAY: case SATURDAY: numLetters = 8; break; case WEDNESDAY: numLetters = 9; break; }; switch (day) { case MONDAY, FRIDAY, SUNDAY: numLetters = 6; break; case TUESDAY: numLetters = 7; break; case THURSDAY, SATURDAY: numLetters = 8; break; case WEDNESDAY: numLetters = 9; break; };
  18. アロー形式 • ラムダ式のようなアロー(->)が使える • わずらわしい`break`が不要 switch (day) { case MONDAY,

    FRIDAY, SUNDAY: numLetters = 6; break; case TUESDAY: numLetters = 7; break; case THURSDAY, SATURDAY: numLetters = 8; break; case WEDNESDAY: numLetters = 9; break; }; switch (day) { case MONDAY, FRIDAY, SUNDAY -> numLetters = 6; case TUESDAY -> numLetters = 7; case THURSDAY, SATURDAY -> numLetters = 8; case WEDNESDAY -> numLetters = 9; };
  19. 式 switch (day) { case MONDAY, FRIDAY, SUNDAY -> numLetters

    = 6; case TUESDAY -> numLetters = 7; case THURSDAY, SATURDAY -> numLetters = 8; case WEDNESDAY -> numLetters = 9; }; numLetters = switch (day) { case MONDAY, FRIDAY, SUNDAY -> 6; case TUESDAY -> 7; case THURSDAY, SATURDAY -> 8; case WEDNESDAY -> 9; };
  20. yield • switch式において、アロー形式でブロックを使うときや既存の 形式では`yield`で値を返す • Java12でのpreview1ではbreakだったけど、ラベル付きbreak とまぎらわしいのもあって変更された case TUESDAY ->

    { yield 7; }
  21. 言語機能 • Text Blocks(Preview2) • Switch expression(Standard) • Records(Preview) •

    Pattern matching for instanceof(Preview)
  22. Records(Preview) • データをやりとりするための型 • イミュータブル(値が変更できない) • 名前付きタプル • Case class(Scala)

    やData class(Kotlin), @Value(Lombok)
  23. 定義 public record Rec(String name, int count) {} public 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 }
  24. Objectメソッドのバイトコード • Invoke Dynamicが使われている • 実行時に処理コードが生成される • コンパイル時ではない • もし将来のバージョンでより最適な実装に変わったとしても、

    古いバージョンでコンパイルされたコードも新しい実装で動く public final boolean equals(java.lang.Object); Code: 0: aload_0 1: aload_1 2: invokedynamic #27, 0 // InvokeDynamic #0:equals:(LRec;Ljava/lang/Object;)Z 7: ireturn
  25. 次のバージョンでは • Sealed Classes(Java15でJEP360としてPreview) • 継承するクラスを限定できる(インタフェースでもよい) • Switch式でdefaultが不要になる public sealed

    class Shape permits Circle, Rectangle, Square {...} Shape rotate(Shape shape, double angle) { return switch (shape) { case Circle c -> c; // no action needed case Rectangle r -> r.rotate(angle); case Square s -> s.rotate(angle); } }
  26. 言語機能 • Text Blocks(Preview2) • Switch expression(Standard) • Records(Preview) •

    Pattern matching for instanceof(Preview)
  27. Pattern Matching for instanceof(Preview) • 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()); }
  28. Byte code public static void main(java.lang.String...); Code: 0: ldc #7

    // String test 2: astore_1 3: aload_1 4: astore_3 5: aload_3 6: instanceof #9 // class java/lang/String 9: ifeq 35 12: aload_3 13: checkcast #9 // class java/lang/String 16: dup 17: astore_2 18: aload_3 19: checkcast #9 // class java/lang/String 22: if_acmpne 35 25: getstatic #11 // Field java/lang/System.out:Ljava/io/PrintStream; 28: aload_2 29: invokevirtual #17 // Method java/lang/String.length:()I 32: invokevirtual #21 // Method java/io/PrintStream.println:(I)V 35: return Object o = "test"; if (o instanceof String s) { System.out.println(s.length()); }
  29. Byte code public static void main(java.lang.String...); Code: 0: ldc #7

    // String test 2: astore_1 3: aload_1 4: astore_3 5: aload_3 6: instanceof #9 // class java/lang/String 9: ifeq 35 12: aload_3 13: checkcast #9 // class java/lang/String 16: dup 17: astore_2 18: aload_3 19: checkcast #9 // class java/lang/String 22: if_acmpne 35 25: getstatic #11 // Field java/lang/System.out:Ljava/io/PrintStream; 28: aload_2 29: invokevirtual #17 // Method java/lang/String.length:()I 32: invokevirtual #21 // Method java/io/PrintStream.println:(I)V 35: return Object o = "test"; if (o instanceof String s) { System.out.println(s.length()); } 無駄では?
  30. Byte code - cast public static void main(java.lang.String...); Code: 0:

    ldc #7 // String test 2: astore_1 3: aload_1 4: instanceof #9 // class java/lang/String 7: ifeq 25 10: aload_1 11: checkcast #9 // class java/lang/String 14: astore_2 15: getstatic #11 // Field java/lang/System.out:Ljava/io/PrintStream; 18: aload_2 19: invokevirtual #17 // Method java/lang/String.length:()I 22: invokevirtual #21 // Method java/io/PrintStream.println:(I)V 25: return Object o = "test"; if (o instanceof String) { String s = (String) o; System.out.println(s.length()); }
  31. Byte code(Java 15 ea 22) public static void main(java.lang.String...); Code:

    0: ldc #7 // String test 2: astore_1 3: aload_1 4: astore_3 5: aload_3 6: instanceof #9 // class java/lang/String 9: ifeq 27 12: aload_3 13: checkcast #9 // class java/lang/String 16: astore_2 17: getstatic #11 // Field java/lang/System.out:Ljava/io/PrintStream; 20: aload_2 21: invokevirtual #17 // Method java/lang/String.length:()I 24: invokevirtual #21 // Method java/io/PrintStream.println:(I)V 27: return ここでは無駄だけどもっと複雑な式の場合には必要。きっとJITで省かれる Object o = "test"; if (o instanceof String s) { System.out.println(s.length()); }
  32. これからのバージョンでは • Pattern with switch • switchでパターンマッチを使う • Deconstruction •

    レコードの分解 switch (obj) { case String s -> parseInt(s); case Integer i -> i; default -> 0; } switch (obj) { case Add(int l, int r) -> l + r; // record Add(int l, int r) case Sub(int l, int r) -> l - r; // record Sub(int l, int r) case Num(int i) -> i; // record Num(int i) default -> throw new UnsupportedOparation(); }
  33. ライブラリ • Helpful NullPointerException • JFR event streaming • Foreign

    Memory Access(Incubator)
  34. ライブラリ • Helpful NullPointerException • JFR event streaming • Foreign

    Memory Access(Incubator)
  35. Helpful NullPointerException • JavaプログラマはNPEが大好きだけどメッセージが不親切 • Java 14ではNPEのメッセージが親切になる String s =

    null; println(s.length()); Exception in thread "main" java.lang.NullPointerException at Sample.main(mysample.java:4) String s = null; println(s.length()); Exception in thread "main" java.lang.NullPointerException: Cannot invoke "String.length()" because "Sample.s" is null at Sample.main(mysample.java:4)
  36. これでもっとNPEが大好きに!

  37. Helpful NullPointerException • `-XX:+ShowCodeDetailsInExceptionMessages`が必要 • 将来のバージョンではデフォルトに • JShellの場合 • `-R-XX:+ShowCodeDetailsInExceptionMessages`をつける

  38. ライブラリ • Helpful NullPointerException • JFR event streaming • Foreign

    Memory Access(Incubator)
  39. JFRとは? • JFR(JDK Flight Recorder) はOpenJDK 11でオープンソースと して導入 • それまではOracle

    JDKの商用機能だった • 名前もJava Flight Recorder • 飛行機のフライトレコーダのようにJVMの実行時の状況を確認 する • データはファイルにダンプされる • 同じくオープンソース化されたJMCで データを見る • (JDK Mission Control)
  40. JFR Event Streaming • イベントとして処理できるようになったので監視に使いやすく なった

  41. ライブラリ • Helpful NullPointerException • JFR event streaming • Foreign

    Memory Access(Incubator)
  42. Foreign Memory Access API • Javaヒープ外のメモリを扱う • 大きいメモリ • GCの影響を排除する

    • これまでのオフヒープメモリの利用方法 • Unsafe • 安全ではない • 解放済みメモリにアクセスするとJVMがクラッシュする • nioのDirect ByteBuffer • intでインデックスアクセスするので2GBまで • メモリの解放はGC依存 • JNI • めんどい • Cヘッダーが必要 • 遅い
  43. @PreviewFeature • Java 13まで • preview機能用のAPIは単に@Deprecated • ‘—enable-feature’なしで使えていた • Java

    14から • @PreviewFeatureアノテーションが導入された • preview機能関連のAPIを使うには‘—enable-feature’が必要 • String#formatted
  44. ツール • Packaging Tool(Incubator)

  45. Packaging Tool • Javaランタイムを含んだアプリケーションパッケージ • ネイティブのパッケージングフォーマット • Windows • exe,

    msi • macOS • pkg, dmg • Linux • deb, rpm
  46. 手順 • コンパイル • javac App.class • JARの作成 • jar

    cf target/app.jar App.class • パッケージの作成 • jpackage --name myapp --input target --main-jar app.jar --main- class App
  47. 結果 • 45MBのインストーラ • 124MBのアプリサイズ • アンインストーラも作成される • メニューの登録 •

    --win-menu
  48. もっとコンパクトにしたい場合 • カスタムランタイム • 最低限のモジュールを含んだJavaランタイム • カスタムランタイムの作成 • jlink --add-modules

    `jdeps --print-module-deps App.class` --output myrt • カスタムランタイムを使ったパッケージの作成 • jpackage --name myapp_min --input target --main-jar app.jar -- main-class App --runtime-image myrt • 結果 • 28MBのインストーラ、78MBのアプリ
  49. もっと詳しく • 「Java 14」でぐぐる