Upgrade to Pro — share decks privately, control downloads, hide ads and more …

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

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

Naoki Kishida

September 28, 2020
Tweet

More Decks by Naoki Kishida

Other Decks in Programming

Transcript

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

    View Slide

  2. 自己紹介
    • きしだ なおき(@kis)
    • LINE Fukuoka
    • 最近 洗濯機がある生活をはじめて
    パンツは4枚くらいあれば回せるんだなと気づく

    View Slide

  3. Java 15で変更された言語機能
    • Records(Second Preview)
    • Pattern Matching for instanceof(Second Preview)
    • 変更なし
    • Sealed Classes(Preview)
    • Text Blocks(Standard)
    • 変更なし

    View Slide

  4. Preview機能
    • 言語機能の試用版
    • 基本的にpreview, second previewの2回のpreviewを経て正式
    化する
    • 正式化までに3バージョン必要
    • 明確な決まりがあるわけではない
    • javacやjavaコマンドなどで`--enable-preview`が必要
    • `-source`でのバージョン指定も必要

    View Slide

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

    View Slide

  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
    オブジェクトの基本メソッドも
    実装される

    View Slide

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

    View Slide

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

    View Slide

  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);
    }
    }
    フィールド初期化が必須
    パラメータを省略
    フィールド初期化
    してはいけない

    View Slide

  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());
    }

    View Slide

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

    View Slide

  12. ( ´∀`)<シールドクラス
    • 公式にはシール・クラス?

    View Slide

  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 "正方形";
    }
    }

    View Slide

  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 {}

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

  19. Switch式のおさらい
    • Switchがステートメントとしてだけではなく式として使える
    • Java 14で標準化
    int numLetters = switch (day) {
    case MONDAY, FRIDAY, SUNDAY -> 6;
    case TUESDAY -> 7;
    case THURSDAY, SATURDAY -> 8;
    case WEDNESDAY -> 9;
    }

    View Slide

  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;
    };

    View Slide

  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;
    };

    View Slide


  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;
    };

    View Slide

  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 "正方形";
    }
    }

    View Slide

  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);
    }
    }

    View Slide

  25. これでなにがしたいの?
    • Optionalをパターンマッチングしたい

    View Slide

  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"
    }
    } ※ コードはイメージです
    定義
    利用

    View Slide

  27. 必要な構造
    • Optionalがinterfaceになる必要がある・・・
    • リフレクションで非互換性がでる
    • Sealed Classesがない場合は自由にimplementできてしまうの
    でfinal classになっていた
    Optional
    Some None

    View Slide

  28. Optionalのパターンマッチング
    • こんなコードが書けるとうれしい
    String foo(Optional opt) {
    return switch(opt) {
    Some(var s) -> "message is %s".formatted(s);
    None -> "empty message";
    };
    }

    View Slide

  29. つまりSealed Classesは
    • Deconstructionでは親クラス・子クラスを公開する
    必要がある
    • その上でユーザーに継承させないという制限ができなかった
    • final or not
    • だれにも継承できないか、だれでも継承できる
    • Sealed Classによって継承を制限できる
    • 安心してDeconstructionを前提にしたクラス構造が設計できる

    View Slide

  30. まとめ
    • 「使える」パターンマッチングの導入が最終目標
    • 機能をうまく分解して導入している
    • 全部そろったときにあわてないよう予習しておきましょう

    View Slide