Amberで検討されているJava構文の変更

# Amberとは

Java言語を拡張するプロジェクトです
http://openjdk.java.net/projects/amber/

# Amberのブランチ
https://github.com/openjdk/amber/branches

- records  
データ保持用のクラスです
- sealed-types  
シールドタイプ
- newesapes  
line blockのエスケープ対応
- patterns  
パターンマッチの全体的な開発
- patterns-deconstruction  
パターンマッチでのデコンストラクション
- patterns-stage-1  
instanceofのみのパターンマッチ
- pattern-runtime  
パターンマッチのランタイム？
- local-methods  
ローカルメソッド
- lambda-leftovers  
ラムダで_使えるようにする
- concise-method-declarations  
メソッド定義の簡略化
- enhanced-enums  
拡張enum
- stats-before-this-super  
なぞ
- amber-demo-II  
switch式とパターンマッチが動いてた

これが、JDK14、15、16...と半年ごとに五月雨式にリリースされていくことになると思います。結構恐怖ですね。

# Records[second preview in JDK15, preview in JDK14]
データ保持用のクラスです。
JEPはこちらで14にPreviewとして入って15でsecond previewになっています。
[JEP 384: Records (Second Preview)](https://openjdk.java.net/jeps/384)
[JEP 359: Records (Preview)](http://openjdk.java.net/jeps/359)
Java 15でpreview 2を経てJava 16で正式化という流れ。

~~JEPは今のところ見当たりません。~~ ~~JEPのドラフトはこちら~~
~~[JEP draft: Records and Sealed Types](http://openjdk.java.net/jeps/8222777)~~

http://cr.openjdk.java.net/~briangoetz/amber/datum.html
http://hg.openjdk.java.net/amber/amber/file/15a61b5af8f5/test/langtools/tools/javac/datum

recordとして定義します。

```java
record Foo(int x, int y) {}
```

他のクラスは継承できません。

```
record レコード名(状態) { 定義 }
```

これは次のようなクラスになります。

```java
class Foo extends Record{
  // 状態がprivate finalとして定義
  private final int x;
  private final int y;
  // 追加のインスタンスフィールドは定義できない

  // 状態をフィールドに設定するコンストラクタが定義される
  public Foo(int x, int y) {
    this.x = x;
    this.y = y;
  }

  // 状態と同じ名前のメソッドが定義される
  public int x() {
    return x;
  }
  public int y() {
    return y;
  }

  // 状態を反映するhashCodeが定義される
  public int hashCode() { ... }
  // 状態を比較するequals が定義される
  public boolean equals() { ... }
  // 状態を表示するtoStringが定義される
  public String toString() { ... }
}
```

状態の検査や正規化にコンストラクタが定義できます。

```java
record Range(int lo, int hi) {
  public Range {
    if (lo > hi) throw IllegalArgumentException();
    // 設定されなかったフィールドはあとで設定される
  }
}
```

Preview 2での改善点はこちらで提案されています。
https://mail.openjdk.java.net/pipermail/amber-spec-experts/2020-January/001913.html

- `java.util.Record`はクラスですが、Valhallaのinline classはinterfaceしか継承できないので、これをinterfaceにしたほうがいいかどうか。
- 必須メンバーへの可視性(private recordのメンバがpublicなのはおかしい？)
- 現状ではstaticではないinner classではrecordを入れ子にすることができないけど対応したい
- abstract record
- パターンマッチでのdeconstructionへの対応

# Sealed Classes[preview in JDK 15]
継承を限定するsealed型も進められています。
[JEP 360: Sealed Classes(Preview)](http://openjdk.java.net/jeps/360)
Sealed TypesからSealed Classesになりました。
~~recordとセットでsealed型の仕様も決められています。~~
~~[JEP draft: Records and Sealed Types](http://openjdk.java.net/jeps/8222777)~~
JDK15でpreviewに入ると思われます。

継承を限定することができます。パターンマッチング用

```
sealed interface Node 
  permits A, B, C {}
```

Nodeを実装するのは`permits`で指定したA, B, Cクラスということになります。同じコンパイル単位に入っていれば`permits`は省略できます。
sealed型を継承するinterfaceや抽象クラスはsealed型になります。sealed型を実装・継承する非抽象クラスはfinalになります。

```
sealed interface Expr {};

record AddExpr(Expr a, Expr b) implements Expr {}
record SubExpr(Expr a, Expr b) implements Expr {}
record MulExpr(Expr a, Expr b) implements Expr {}
record DivExpr(Expr a, Expr b) implements Expr {}
```

`non-sealed`というハイフン区切りのキーワードが入るのも面白いです。

# パターンマッチング[second preview in JDK 15, preview in JDK 14]
パターンマッチングです。
まずはinstanceofを使ったパターンマッチが14にプレビューとして入り15でsecond previewになっています。
[JEP 375: Pattern Matching for instanceof (Second Preview)](https://openjdk.java.net/jeps/375)
[JEP 305: Pattern Matching for instanceof (Preview)](https://openjdk.java.net/jeps/305)

`値 instanceof パターン`で、値をマッチさせることができます。
パターンは、定数か変数定義です。変数定義の場合には、型が一致していた場合にtrueになりその変数に値が割り当てられます。

```java
if (x instanceof Integer i) {
    // can use i here
}
```

16以降になりますがswitchでもパターンマッチが使えます。
[JEP draft: Pattern matching for switch (Preview)](http://openjdk.java.net/jeps/8213076)

```java
String formatted;
switch (obj) {
    case Integer i: formatted = String.format("int %d", i); break;
    case Byte b:    formatted = String.format("byte %d", b); break;
    case Long l:    formatted = String.format("long %d", l); break;
    case Double d:  formatted = String.format("double %f", d); break;
    case String s:  formatted = String.format("String %s", s); break
    default:        formatted = obj.toString();
}
```

まだJEPになってませんが、データクラスと組み合わせて構造の分解を行うことができるようになるということも目標です。

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

そうすると、switchでdoubleやbooleanも使えるようになるかもしれません。

```java
switch (obj) {
  case 12 :   msg = "12だ"; break;
  case true : msg = "とぅるー"; break;
  case 3.14:  msg = "円周率では"; break;
}
```


# 拡張switch[standard in JDK 14, preview in JDK 12,13]
いままでステートメントであった`switch`を式として使えるようになります。Java 12でプレビューとして導入され、Java 13で仕様変更、そしてJava 14で正式機能として導入されるようです。
https://openjdk.java.net/jeps/361

プレビューのJEP
https://openjdk.java.net/jeps/325
https://openjdk.java.net/jeps/354

`switch`はステートメントでしたが、多くのswitchで同一の変数に値を割り当てたりすべてのcaseでreturnしたりといった使いかたがされていたため、効率的に書けるように式としても使えるようになります。

つまり、こう。

```java
int numLetters = switch (day) {
    case MONDAY, FRIDAY, SUNDAY -> 6;
    case TUESDAY -> 7;
    case THURSDAY, SATURDAY -> 8;
    case WEDNESDAY -> 9;
};
```

`yield`で値を返すということもできます。

```java
int result = switch (s) {
    case "Foo":
        yield 1;
    case "Bar":
        yield 2;
    default:
        System.out.println("Neither Foo nor Bar, hmmm...");
        yield 3;
}
```

基本的な形は`yield`で値を返すものです。

```java
case LABEL: yield expression;
```

そのシンタックスシュガーとしてラムダっぽく書けるということのようです。

```java
case LABEL -> expression;
```

また、`case`に複数の値を指定できるようにもなります。

```java
switch (day) {
    case MONDAY, FRIDAY, SUNDAY: 
        numLetters = 6;
        break;
    ...
};
```

このような`case`の拡張は、既存の`switch`ステートメントでも有効です。

`case`に`null`も使えるようになるはずだったけど、JEP325からは外れてるようですね。

```java
String formatted = switch (s) {
    case null -> "(null)";
    case "" -> "(empty)";
    default -> s;
}
```

`case null`がない場合には次のような`case`が自動的に挿入されます。

```java
case null: throw new NullPointerException();
```

# 文字列リテラルの拡張[standard in JDK 15, preview in JDK 13,14]

https://openjdk.java.net/jeps/378
https://openjdk.java.net/jeps/368

改行などを含んだ文字列を定義できます。`"""`で囲みます。
JDK13にPreviewとして入っています。
https://openjdk.java.net/jeps/355

JDK14では改行のエスケープなど少し仕様変更が入りました。JDK15でstandardになる予定。

最初はRaw String LiteralsとしてJDK12に入る予定でしたが、却下されました。
~~http://openjdk.java.net/jeps/326~~

```java
// same as "You can write\ntwo line string.\n"
var str = """
  You can write
  two line string.
  """;
```

開始の`"""`のあとには文字列を続けれません。また、インデントは`"""`や内部の文字列で一番浅いところが基準になります。

```java
var str = """
..You can write
..two line string.
  """;
```

```java
var str = """
..  You can write
..  two line string.
  """;
```

改行をエスケープすることもできます。

```java
var str = """
  You can write \
  two line string, \
  but this is single.
  """;
```

これは`"You can write two line string, but this is single."`になります。

行末のスペースは削除されます。
そこで、行末にスペースが必要なときは`\s`を入れてスペースが必要なことを示します。

```java
var str = """
  test\s
  test \s
  """;
```

これは`"test_\ntest__\n"`になります。(Qiitaでは複数スペースをいれてもスペースひとつになってしまう)


関係ないけどQiitaが```のようにバッククオートをバッククオートで囲めないので困る人が続出する気がする。
2018/5/8時点では次のようにレンダリングされている。
<img width="679" alt="スクリーンショット 2018-05-08 4.38.25.png" src="https://qiita-image-store.s3.amazonaws.com/0/228058/2830f785-580e-e0eb-d9df-d7605bf552cb.png">

# ラムダの微修正
ラムダの微修正
http://openjdk.java.net/jeps/302

使わない変数に`_`を使えます。

```java
BiFunction<Integer, String, String> biss = (i, _) -> String.valueOf(i);
```

あと、次のような場合、`false`を返すので`Predicate`になることは明確ですが、現状ではエラーになってます。これをちゃんと型推論できるようにしようというもの。

```java
m(Predicate<String> ps) { ... }
m(Function<String, String> fss) { ... }

m(s -> false) //ambiguous
```


# 拡張enum[取り下げ]
enumでgenericsを指定できるようにしようというものです。
http://openjdk.java.net/jeps/301

```java
enum Argument<X> { // declares generic enum
   STRING<String>(String.class), 
   INTEGER<Integer>(Integer.class), ... ;

   Class<X> clazz;

   Argument(Class<X> clazz) { this.clazz = clazz; }

   Class<X> getClazz() { return clazz; }
}

Class<String> cs = Argument.STRING.getClazz(); //uses sharper typing of enum constant
```

withdrawn、取り下げになりました。

# メソッド定義の簡略化

http://openjdk.java.net/jeps/8209434

メソッド定義で`->`を使えるようにする

```java
int twice(int x) -> x * x;
```

メソッド参照は`=`で

```java
int min(int x, int y) = Integer::min;
```

オーバーロード・オーバーライドなどでの移譲がすっきり書けます。

# ローカルメソッド

2019/11/16時点ではJEPなどはないですが、amberリポジトリのブランチを見ると、メソッドの中でメソッドが定義できるようになる拡張をやってる気配があります。

次のようにメソッド内メソッドの定義ができるようにするものです。

```java
int norm(int x, int y) {
  int square(int n) {
    return n * n;
  }
  return square(x) + square(y);
}
```

メソッド定義の簡略化と組み合わせると次のように書けるようになるはず

```java
int norm(int x, int y) {
  int square(int n) -> n * n;
  return square(x) + square(y);
}
```


# ローカル変数型推論[standard in JDK10]
ローカル変数の型推論を導入するものです。
http://openjdk.java.net/jeps/286

```java
var x = 12;
```

JDK 10で導入されています。

# ラムダへのvar対応[standard in JDK11]
ラムダの変数定義にも`var`を明示的に書けるようにしようというものです。
http://openjdk.java.net/jeps/323

いままでこう書けていました。

```java
(x, y) -> x + y
```

`var`で明示的に型推論であることを指定しようというものです。

```java
(var x, var y) -> x + y
```

混在はできません

```java
(var x, y) -> x + y
```

JDK 11に入りました。

# 構文以外
condyという名前で、indyのコンストラクタ版が開発されているぽい。
-> Constant Dynamicだった。
http://openjdk.java.net/jeps/309

JDK 11に入りました。