Amberとは
Java言語を拡張するプロジェクトです
http://openjdk.java.net/projects/amber/
Amberのブランチ
http://hg.openjdk.java.net/amber/amber/branches
- datum データクラス
- patterns パターンマッチ
- switch 拡張switch
- lambda-leftovers ラムダの微修正
- enhanced-enums 拡張enum
- lvti ローカル変数型推論
これが、JDK10、11、12...と半年ごとに五月雨式にリリースされていくことになると思います。結構恐怖ですね。
データクラス
データ保持用のクラスです。
JEPは今のところ見当たりません。
http://hg.openjdk.java.net/amber/amber/file/c6ca12231746/test/langtools/tools/javac/datum
recordとして定義します。
record Foo(int x, int y) {}
継承できるのはAbstract recordのみ
abstract record Sup(int x, int y) {}
record Bar(int x, int y, int z) extends Sup(x, y);
スーパーrecordに渡すのは同じ名前でないといけない
明示的にコンストラクタを定義する場合の値の設定はdefault
を使う
record Foo(int x, int y) {
Foo(int x, int y) {
default(x, y);
}
}
ガードとして条件を指定できる
record Range1(int lo, int hi) where lo <= hi;
record Range2(int lo, int hi) where lo <= hi {};
パターンマッチング
パターンマッチングです。
http://openjdk.java.net/jeps/305
値 matches パターン
で、値をマッチさせることができます。
パターンは、定数か変数定義です。変数定義の場合には、型が一致していた場合にtrueになりその変数に値が割り当てられます。
if (x matches Integer i) {
// can use i here
}
switchでもパターンマッチが使えます。
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();
}
つまり、switchでdoubleやbooleanも使えるようになるということです。
switch (obj) {
case 12 : msg = "12だ"; break;
case true : msg = "とぅるー"; break;
case 3.14: msg = "円周率では"; break;
}
JEP 305には含まれませんが、データクラスと組み合わせて構造の分解を行うことができるようになるということも目標です。
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
http://openjdk.java.net/jeps/325
switch
はステートメントでしたが、多くのswitchで同一の変数に値を割り当てたりすべてのcaseでreturnしたりといった使いかががされていたため、式としても使えるようになります。
つまり、こう。
int numLetters = switch (day) {
case MONDAY, FRIDAY, SUNDAY -> 6;
case TUESDAY -> 7;
case THURSDAY, SATURDAY -> 8;
case WEDNESDAY -> 9;
};
break
で値を返すということもできます。
int result = switch (s) {
case "Foo":
break 1;
case "Bar":
break 2;
default:
System.out.println("Neither Foo nor Bar, hmmm...");
break 3;
}
基本的な形はbreak
で値を返すものです。
case LABEL: break expression;
そのシンタックスシュガーとしてラムダっぽく書けるということのようです。
case LABEL -> expression;
case
にnull
も使えるようになります。
String formatted = switch (s) {
case null -> "(null)";
case "" -> "(empty)";
default -> s;
}
case null
がない場合には次のようなcase
が自動的に挿入されます。
case null: throw new NullPointerException();
また、case
に複数の値を指定できるようにもなります。
switch (day) {
case MONDAY, FRIDAY, SUNDAY:
numLetters = 6;
break;
...
};
このようなcase
の拡張は、既存のswitch
ステートメントでも有効です。
ラムダの微修正
ラムダの微修正
http://openjdk.java.net/jeps/302
使わない変数に_
を使えます。
BiFunction<Integer, String, String> biss = (i, _) -> String.valueOf(i);
あと、次のような場合、false
を返すのでPredicate
になることは明確ですが、現状ではエラーになってます。これをちゃんと型推論できるようにしようというもの。
m(Predicate<String> ps) { ... }
m(Function<String, String> fss) { ... }
m(s -> false) //ambiguous
拡張enum
enumでgenericsを指定できるようにしようというものです。
http://openjdk.java.net/jeps/301
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
ローカル変数型推論
ローカル変数の型推論を導入するものです。
http://openjdk.java.net/jeps/286
var x = 12;
JDK 10で導入されることが決まっています。
ラムダへのvar対応
ラムダの変数定義にもvar
を明示的に書けるようにしようというものです。
http://openjdk.java.net/jeps/323
いままでこう書けていました。
(x, y) -> x + y
var
で明示的に型推論であることを指定しようというものです。
(var x, var y) -> x + y
混在はできません
(var x, y) -> x + y
JDK 11に入りそう。