めでたくJDK 21がリリースされたので多少試していたわけですが、switch式に色々と網羅性検査が入ったわけで、Scalaと比較してどうなるか?を試したメモ。
switchで全てを網羅していないと、Javaはcompile errorで、Scalaはデフォルトでは警告なので、ScalaよりJavaの方が安全だぞ!!!(適当)
— Kenji Yoshida (@xuwei_k) September 24, 2023
JavaでもScalaでのMatchErrorと同じような例外classが新たに用意されて、最悪それがthrowされるらしいです。 網羅してないとScalaと違ってJavaではコンパイルエラーとはいえ、頑張ればいくらでも原理上は発生させられるはずで、発生させるサンプルを作った、というだけの話。
発生させる方法も、他にもいくらでもありそうだけれど、とりあえずsealed interfaceとrecordでやってみた
- https://docs.oracle.com/en/java/javase/21/docs/api/java.base/java/lang/MatchException.html
- https://github.com/openjdk/jdk/blob/3d6e775d7135919519a9748036cd20b6c130bb42/src/java.base/share/classes/java/lang/MatchException.java
以下、手順。
以下の2つのファイル用意してコンパイル
A.java
package example; public sealed interface A { public record B(int x) implements A{} }
F.java
package example; public class F { public static int f(A a) { return switch(a) { case A.B b -> b.x(); }; } }
次に A.java
と F.java
を以下のように改変してコンパイル。また、 Main.java
用意
public sealed interface A {
public record B(int x) implements A{}
+ public record C(int x) implements A{}
}
public static int f(A a) {
return switch(a) {
case A.B b -> b.x();
+ case A.C c -> c.x();
};
}
Main.java
package example; public class Main { public static void main(String[] args) { System.out.println(F.f(new A.C(3))); } }
そして
- 古いほうの
F
( = 分岐がB
の1つしか書いてないもの) - 新しい方の
A
とMain
( =C
が増えてる。C
をメソッドに渡してる)
を組み合わせて実行する。と以下のようなエラーになる
Exception in thread "main" java.lang.MatchException at example.F.f(F.java:5) at example.Main.main(Main.java:5)
ところで、javapしてもエラーメッセージからしても、せっかく引数があるのに null
しか渡してない気がするのはどうして・・・?
44: new #17 // class java/lang/MatchException 47: dup 48: aconst_null 49: aconst_null 50: invokespecial #19 // Method java/lang/MatchException."<init>":(Ljava/lang/String;Ljava/lang/Throwable;)V 53: athrow