Java 15の新機能 Recordsを中心に / New feature in Java 15 around the Records

9e840766611f942c7c0a9ad6987a5d78?s=47 Naoki Kishida
September 28, 2020

Java 15の新機能 Recordsを中心に / New feature in Java 15 around the Records

2020/9/28に開催されたJJUGナイトセミナーでの登壇資料です
https://jjug.doorkeeper.jp/events/111440

9e840766611f942c7c0a9ad6987a5d78?s=128

Naoki Kishida

September 28, 2020
Tweet

Transcript

  1. Java 15の新機能 Recordsを中心に LINE Fukuoka きしだ なおき 2020/9/28 JJUG ナイトセミナー

  2. 自己紹介 • きしだ なおき(@kis) • LINE Fukuoka • 最近 洗濯機がある生活をはじめて

    パンツは4枚くらいあれば回せるんだなと気づく
  3. Java 15で変更された言語機能 • Records(Second Preview) • Pattern Matching for instanceof(Second

    Preview) • 変更なし • Sealed Classes(Preview) • Text Blocks(Standard) • 変更なし
  4. Preview機能 • 言語機能の試用版 • 基本的にpreview, second previewの2回のpreviewを経て正式 化する • 正式化までに3バージョン必要

    • 明確な決まりがあるわけではない • javacやjavaコマンドなどで`--enable-preview`が必要 • `-source`でのバージョン指定も必要
  5. Records(2nd Preview) • データをやりとりするための型 • イミュータブル(値が変更できない) • 名前付きタプル • Case

    class(Scala) やData class(Kotlin), @Value(Lombok)
  6. 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で宣言 コンポーネントに 対応するフィールド private final java.lang.Recordを継承 暗黙にfinal コンストラクタが定義される コンポーネントと同名の アクセスメソッド not getter オブジェクトの基本メソッドも 実装される
  7. Recordの利用 • 利用時は普通のクラスと同様 Rec r = new Rec("Java", 15);

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

  9. コンパクトコンストラクタ • 必ず書かないといけないものは省略していいのでは? record Rec(String name, int count) { Rec(String

    name, int count) { this.name = name; this.count = Math.max(count, 0); } } record Rec(String name, int count) { Rec { count = Math.max(count, 0); } } フィールド初期化が必須 パラメータを省略 フィールド初期化 してはいけない
  10. Pattern Matching for instanceof(2nd 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()); }
  11. Sealed Classes • 継承できるクラスを限定する • shield(盾) classではなくてsealed(密閉された) class public abstract

    sealed class Shape permits Circle, Rectangle, Square {...}
  12. ( ´∀`)<シールドクラス • 公式にはシール・クラス?

  13. 現状では使い道なし • 本当は次のように書けるといい • Pattern matching for switchなどが来れば便利に(後半に説明) String getName(Shape

    s) { if (s instanceof Circle) { return "円"; } else if (s instanceof Rectangle) { return "四角"; } else if (s instanceof Square) { return "正方形"; } }
  14. 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 {}
  15. non-sealed • ハイフン入りキーワード! • 実際はキーワードではない • switch式のときにbreak-withが検討されていた • package-privateなども可能

  16. Sealed Classedはなんのため? • パターンマッチングが完成したときに必要 • いまは途中経過

  17. 今後の計画 • Pattern Matching for switch • Deconstruction

  18. Pattern Matching for switch • パターンマッチングをswitch式/文で使えるようにする

  19. Switch式のおさらい • Switchがステートメントとしてだけではなく式として使える • Java 14で標準化 int numLetters = switch

    (day) { case MONDAY, FRIDAY, SUNDAY -> 6; case TUESDAY -> 7; case THURSDAY, SATURDAY -> 8; case WEDNESDAY -> 9; }
  20. 複数の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; };
  21. アロー形式 • ラムダ式のようなアロー(->)が使える • わずらわしい`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; };
  22. 式 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; };
  23. swtichでパターンマッチングが使えるように なると便利 • Pattern matching for switchが導入されてSealed classを使う と、次のようなswitchがdefaultなしで書けるようになる String

    getName(Shape s) { return switch (s) { case Circle c -> return "円"; case Rectangle r -> return "四角"; case Square q -> return "正方形"; } }
  24. Deconstruction • 脱構築? • ジャック・デリダ • 静的な構造を前提とする→構造を分解して新しい構造を構築する • パターンマッチングで構造を分解する record

    Point(int x, int y) {} int getLen(Point p) { return switch (p) { case Point(0, int y) -> y; case Point(int x, 0) -> x; case Point(int x, int y) -> (int)sqrt(x * x + y * y); } }
  25. これでなにがしたいの? • Optionalをパターンマッチングしたい

  26. ScalaのOptionのパターンマッチング • ScalaではOptionがsealed classになっていてパターンマッチン グが使える sealed class Option[A] case class

    Some[A](x: A) extends Option[A] case object None extends Option[Nothing] def a(opt: Option[String]):String = { opt match { case Some(s) => "message is %s" format s case None => "empty message" } } ※ コードはイメージです 定義 利用
  27. 必要な構造 • Optionalがinterfaceになる必要がある・・・ • リフレクションで非互換性がでる • Sealed Classesがない場合は自由にimplementできてしまうの でfinal classになっていた

    Optional Some None
  28. Optionalのパターンマッチング • こんなコードが書けるとうれしい String foo(Optional<String> opt) { return switch(opt) {

    Some(var s) -> "message is %s".formatted(s); None -> "empty message"; }; }
  29. つまりSealed Classesは • Deconstructionでは親クラス・子クラスを公開する 必要がある • その上でユーザーに継承させないという制限ができなかった • final or

    not • だれにも継承できないか、だれでも継承できる • Sealed Classによって継承を制限できる • 安心してDeconstructionを前提にしたクラス構造が設計できる
  30. まとめ • 「使える」パターンマッチングの導入が最終目標 • 機能をうまく分解して導入している • 全部そろったときにあわてないよう予習しておきましょう