JEP361: Switch Expressions
switch 文に新しい表記が追加
- case ラベルについて新しい表記 (
case XXX ->
) を追加- break 文が不要になる
- カンマ区切りで複数の値を指定可能
- 直接値を返すことが可能になった
サンプルコード
public class SwitchExpressions {
public static void main(String[] args) {
newLabel();
returnValue();
}
/**
* case XX: の代用として case XX -> が登場
* case に複数の値をカンマ区切りで指定できる
*
* メリット:"->" の右側のコードのみ実行される (= break 文が不要)
*/
public static void newLabel() {
switch (Calendar.getInstance().get(DAY_OF_WEEK)) {
case MONDAY, TUESDAY, WEDNESDAY, THURSDAY, FRIDAY -> {
System.out.println("平日です。");
System.out.println("ブロックにすれば複数命令も実行できます。");
}
case SATURDAY, SUNDAY -> System.out.println("休日です。");
}
// もちろん今まで通りの書き方もできる
int dayOfWeek = SUNDAY;
switch (dayOfWeek) {
case SATURDAY:
case SUNDAY:
System.out.println("休日");
break;
default:
System.out.println("平日");
}
}
/**
* switch 文から値を返すことが可能。
* 条件によって代入する値を変える処理が簡潔に書けるようになった。
*/
public static void returnValue() {
String dayOfWeek = switch (Calendar.getInstance().get(DAY_OF_WEEK)) {
case MONDAY -> "月曜";
case TUESDAY -> "火曜";
case WEDNESDAY -> "水曜";
case THURSDAY -> "木曜";
case FRIDAY -> "金曜";
case SATURDAY, SUNDAY -> "休日";
default -> "";
};
System.out.println("今日は" + dayOfWeek);
}
}
JEP 378: Text Blocks
複数行にわたる文字列やダブルクォーテーションを含む文字列を簡潔に記述できる。
-
“““
(ダブルクォーテーション 3 つ) で囲む - 開始
“““
の後ろには改行が必要 - 定義した文字列のインデントは閉じ
“““
の位置に合わせて自動調整されるっぽい
関連するものとして String に 3 つのメソッドが追加。
- String::formatted(Object... args)
- 文字列に変数の値を埋め込む
- String::translateEscapes()
- エスケープシーケンスが特殊文字として翻訳される
- String::stripIndent()
- text blocks 同士を結合した場合などの余分な空白の削除
サンプルコード
public class TextBlocks {
public static void main(String[] args) {
html();
autoIndent();
multiDoubleQuote();
additionalMethods();
}
public static void html() {
String str =
"""
<html>
<body>
<p>Hello, world</p>
<input type="text">
</body>
</html>
""";
System.out.println(str);
}
public static void autoIndent() {
String str =
"""
line1: インデントなし
line2: 半角空白でインデント
line3: タブ文字でインデント
""";
System.out.println(str);
}
public static void multiDoubleQuote() {
// """ を文字列として扱いたい場合はいずれかの " をエスケープする必要がある
String str =
"""
1: "
2: ""
3: ""\"
4: ""\""
""";
System.out.println(str);
}
}
JEP 394: Pattern Matching for instanceof
obj instanceof class 変数名
で型判定した後にキャストして変数に代入してくれる。
サンプルコード
public class PatternMatchingForInstanceof {
public static void main(String[] args) {
print("hoge");
print(123);
}
public static void print(Object obj) {
// instanceof [class] tmp で型チェックとキャストを同時に可能
if (obj instanceof String s) {
System.out.println(s + " is String.");
} else {
System.out.println("obj is not String.");
}
/* 以前は型チェック後に自分でキャストが必要だった
if (obj instanceof String) {
String s = (String) obj;
...
*/
}
}
JEP 395: Records
record クラスが正式に導入された。
以下を自動生成してくれる。
- コンストラクタ
- フィールドの getter
- メソッド名はフィールド名と同じ
- equals(), hashCode(), toString()
サンプルコード
public class RecordClass {
public static void main(String[] args) {
User user = new User("山田 太郎", new Address("123-4567", "東京"));
// 各フィールドの値の取得
System.out.println("user.name(): " + user.name());
System.out.println("user.home().zip(): " + user.home().zip());
System.out.println("user.home().address(): " + user.home().address());
User user2 = new User("山田 太郎", new Address("123-4567", "東京"));
System.out.println("user.hashCode(): " + user.hashCode());
System.out.println("user.equals(user2): " + user.equals(user2));
System.out.println("user.toString(): " + user.toString());
}
}
public record User(String name, Address home) {}
public record Address(String zip, String address) {}
JEP 409: Sealed Classes
自クラスを継承するサブクラスを限定することができる。
- sealed class [class name] permits [subclass name] で継承するサブクラスを限定する
- permits に指定するサブクラスと、自クラスを継承しているサブクラスは完全一致させる必要がある
- permits に指定したサブクラスは自クラスを継承して存在している必要がある
- permits に指定していないクラスは自クラスを継承できない
- 自クラスとサブクラスは同じ階層に配置する必要がある
- サブクラスは final にする必要がある = サブクラスを更に継承することは禁止
設計思想としては「enum なら種類数まで限定できるけど、継承ってその情報欠けてるよね?」という感じらしい。
例)太陽系の惑星を enum で定義すれば水星~海王星の 8 つであることが自明になるが、
惑星クラスを水星クラス、金星クラス、…、海王星クラスとしてクラス定義すると
惑星は 8 つであるという情報が欠落する。
サンプルコード
public abstract sealed class SealedClasses
permits Mercury, Venus, Earth {
// 本例では abstract クラスにしているが、別に普通のクラスでも interface でも OK
protected String name;
public static void main(String[] args) {
SealedClasses planet = new Mercury("水星");
planet.printName();
}
public SealedClasses(String name) {
this.name = name;
}
public void printName() {
System.out.println("This planet is " + name + ".");
}
}
public final class Mercury extends SealedClasses {
public Mercury(String name) {
super(name);
}
}
public final class Venus extends SealedClasses {
public Venus(String name) {
super(name);
}
}
public final class Earth extends SealedClasses {
public Earth(String name) {
super(name);
}
}
JEP 406: Pattern Matching for switch (Preview)
Java17 時点ではプレビュー、Java19 でも 3rdプレビュー機能
switch 文の case に null、クラス名を指定できる。
- クラス名を指定する場合はキャストした値を受け取る変数名も一緒に記述する
&& で条件を繋ぐこともできる。
サンプルコード
public class PatternMatchingForSwitch {
public static void main(String[] args) {
System.out.println(branchByClass(null));
System.out.println(branchByClass(10));
System.out.println(branchByClass(12345L));
System.out.println(branchByClass("hogefugafoo"));
System.out.println(branchByClass("hoge"));
System.out.println(branchByClass(3.14));
}
/**
* case の条件部分にクラスと null を指定できる
* -> case [class名] [変数名] の形
* また、&& で条件を繋ぐこともできる
*/
public static String branchByClass(Object obj) {
return switch (obj) {
case null -> String.format("null");
case Integer i -> String.format("int %d, *10 %d", i, i*10);
case Long l -> String.format("long %d", l);
case String s && s.length() >= 5 -> String.format("5 文字以上の文字列 %s", s);
case String s -> String.format("String %s", s);
default -> String.format("non match %s", obj);
};
}
}