Java8初期で知識が止まってる化石プログラマーがJava17を触って得た知見

# はじめに
Java8初期で知識が止まっている化石プログラマーが書籍『[プロになるJava](https://www.amazon.co.jp/dp/B09VK3FTDM/ref=dp-kindle-redirect?_encoding=UTF8&btkr=1)』を読んで、得た知見をメモ書き感覚であげていきます。

初歩的な内容も含まれてますが、温かい目で見守ってください。。

# JShell
CUI上でJavaコードを実行できる。Java9より導入された。
参考：https://qiita.com/nowokay/items/e0b9c676567134e4a622


tabで補完、ドキュメント表示なども可能。

/vで型を確認できる
```shell
jshell> /v textBlock 
|    String textBlock = "改行あり\nの\n文字列です\n"
```

# テキストブロック
Java15から。
`"""`で囲った文字列は複数行の文字列として宣言できる。

```shell
jshell> var textBlock = """
   ...> 改行あり
   ...> の
   ...> 文字列です
   ...> """
textBlock ==> "改行あり\nの\n文字列です\n"
```

また、テキストブロック内ではエスケープ`\`が不要になる。
```shell
jshell> """
   ...> テキストブロック内では"エスケープ"が不要
   ...> """
$16 ==> "テキストブロック内では\"エスケープ\"が不要\n"
```

# BigDecimal
雑に言うと、10進数を扱うための型。

```sh
jshell> var ten = BigDecimal.valueOf(10)
ten ==> 10

jshell> var twenty = BigDecimal.valueOf(20)
twenty ==> 20

jshell> ten.subtract(twenty)
$34 ==> -10


# 足し算
jshell> ten.add(twenty)
$33 ==> 30

# 引き算
jshell> ten.subtract(twenty)
$37 ==> -10

# 掛け算
jshell> ten.multiply(twenty)
$35 ==> 200

# 割り算
jshell> ten.divide(twenty)
$36 ==> 0.5
```

0, 1, 10は定数が用意されている。
```sh
jshell> BigDecimal.ZERO
$40 ==> 0

jshell> BigDecimal.ONE
$38 ==> 1

jshell> BigDecimal.TEN
$39 ==> 10
```

BigDecimalが有用なケースの一つとして、小数計算がある。
有名な話だが、コンピュータは10進数の小数同士の計算が苦手。例えば0.1+0.2なんかは誤差が出てしまう。

```sh
jshell> 0.1+0.2
$24 ==> 0.30000000000000004
```

これは0.1も0.2も10進数→2進数に変換した際に循環小数となってしまうためだ。
参考：http://www.it-license.com/cardinal_number/DecimalToBinary.html

BIgDecimalではこの誤差問題を以下のように回避できる。

```sh
jshell> var b1 = new BigDecimal("0.1")
b1 ==> 0.1

jshell> var b2 = new BigDecimal("0.2")
b2 ==> 0.2

jshell> b1.add(b2)
$27 ==> 0.3
```

[BigDecimal(String val)](https://docs.oracle.com/javase/jp/8/docs/api/java/math/BigDecimal.html#BigDecimal-java.lang.String-)コンストラクタを用いて、`"0.1"` `"0.2"`を扱うことが可能になる。2進数がどうとかは関係なく、コンストラクタ引数に指定した文字列をそのまま数値として扱えるのがミソ。

なお、valueOfでもOK
```sh
jshell> var b3 = BigDecimal.valueOf(0.1)
b3 ==> 0.1

jshell> var b4 = BigDecimal.valueOf(0.2)
b4 ==> 0.2

jshell> b3.add(b4)
$45 ==> 0.3
```

# switch
switch文の書き方がJava14から変更されている。
変更点は、それぞれのcaseにbreakが不要になったのと、ラムダっぽく`->`を使える点である。

```java
        var num = 1;

        // Java14〜
        switch (num) {
            case 0 -> System.out.println("ZERO");
            case 1 ->  System.out.println("ONE");
            case 2 ->  System.out.println("TWO");
            default ->  System.out.println("OTHER");
        }

        // 〜Java13
        switch (num) {
            case 0:
                System.out.println("ZERO");
                break;
            case 1:
                System.out.println("ONE");
                break;
            case 2:
                System.out.println("TWO");
                break;
            default:
                System.out.println("OTHER");
                break;
        }
```

switchに値を返させることも可能。
```java
        var num = 1;

        var numStr = switch (num) {
            case 0 -> "ZERO";
            case 1 ->  "ONE";
            case 2 ->  "TWO";
            default ->  "OTHER";
        };

        System.out.println(numStr); //ONE
```

## The yield Keyword

# record
Java16より、recordを使うことで型の違うデータをまとめて扱うことができる。
```sh
jshell>         record Person(String name, int age) {}
   ...>         var p1 = new Person("一郎", 10);
   ...> 
|  次を作成しました: レコード Person
p1 ==> Person[name=一郎, age=10]

jshell> p1.name()
$5 ==> "一郎"

jshell> p1.age()
$6 ==> 10

jshell> p1.name().length()
$7 ==> 2
```

プロパティへのアクセスは`name()` `age()`で可能。
Listにもつめれるので、Streamで色々処理できそうな予感。
```sh
jshell>         var p2 = new Person("二郎", 20);
   ...>         var p3 = new Person("三郎", 30);
p2 ==> Person[name=二郎, age=20]
p3 ==> Person[name=三郎, age=30]

jshell>         var persons = List.of(p1, p2, p3);
   ...> 
persons ==> [Person[name=一郎, age=10], Person[name=二郎, age=20], Person[name=三郎, age=30]]
```

recordの中にメソッドを定義することも可能。
```java
        record Person(String name, int age) {
            public String getUpper(){
                return this.name.toUpperCase();
            }
        }

        var p1 = new Person("ichiro", 10);

        System.out.println(p1.getUpper()); //ICHIRO
```

もちろん外部クラスとして定義することも可能。
```java:ManRecord.java
public record ManRecord(String name, int age) {
    // メソッドなど・・・
}
```

DTOクラスとかは今後Recordに置き換わっていくのかな・・・？
と思ったけど、継承ができないので、基底クラスで共通化なんかしてると移行は難しそうな予感。
継承を使わないようなDTO設計が求められるのか？
参考：https://irof.hateblo.jp/entry/2021/09/23/235642

Java17～は既存のDTOクラスは「Recordに置換しますか？」とweak warningを出すらしく、やはりrecordへの移行を促していそう。

# メソッド参照の使い所
メソッド参照自体はJava8からあるのですが、IDEに補完してもらわないとなかなか気づけないことが多いワタクシ。メソッド参照を使える条件を再確認すると、以下のような感じ。

```java
引数 -> インスタンス.メソッド(引数)
```
↓
```java
クラス::メソッド
```

受け取った引数をstaticメソッドに渡している
→引数を省略して、クラス名とメソッド名だけ書く
※staticメソッドの場合も大体同じ。


＜例1＞
```java
x -> someInstance.doSomething(x)
```
↓
```java
SomeInstance::doSomething
```
＜例2＞
```java
s -> System.out.println(s)
```
↓
```java
System.out::println
```


# Pattern Matching of instanceof
Java 16


# Sealed Classes
Java 17

# 参考
https://reflectoring.io/java-release-notes/