Msc*_*scG 5 java record pattern-matching java-19
我从这里下载了 JDK19 的候选版本https://jdk.java.net/19/以尝试一下那里实现的新记录模式,但我遇到了一些问题。在我的测试中,我写了一个基于密封接口加记录的Optional版本,方式如下:
package tests.patterns;
import java.util.Objects;
public class TestRecordPatter
{
public static void main(final String[] args)
{
final Opt<String> opt1 = computeAnswer(23);
final String answer1 = switch (opt1) {
case Opt.Some<String>(String ans) -> ans;
case Opt.None __ -> "no answer";
default -> throw new IllegalStateException("This should not happen"); // A
};
System.out.println(answer1);
final Opt<String> opt2 = computeAnswer(35);
final Object answer2 = switch (opt2) { // B
case Opt.Some<String>(var ans) -> ans; // C
case Opt.None __ -> "no answer";
default -> throw new IllegalStateException("This should not happen"); // A-2
};
System.out.println(answer2);
final Opt<String> opt3 = computeAnswer(84);
final String answer3 = switch (opt3) { // D
case Opt.Some<String> s -> s.value();
case Opt.None __ -> "no answer";
};
System.out.println(answer3);
}
private static Opt<String> computeAnswer(final int question)
{
if (question % 2 == 0) {
return Opt.some(String.valueOf(question / 2));
} else {
return Opt.none();
}
}
private sealed interface Opt<T> permits Opt.Some, Opt.None
{
static <T> Opt<T> of(final T value)
{
return value == null ? none() : some(value);
}
static <T> Opt<T> some(final T value)
{
return new Opt.Some<>(value);
}
@SuppressWarnings("unchecked")
static <T> Opt<T> none()
{
return Opt.None.NONE;
}
record Some<T>(T value) implements Opt<T>
{
public Some
{
Objects.requireNonNull(value, "Value must not be null");
}
}
@SuppressWarnings({ "rawtypes" })
enum None implements Opt
{
NONE;
}
}
}
Run Code Online (Sandbox Code Playgroud)
第一个 switch 表达式使用记录解构来使用变量的显式类型从 Some 变体中获取值,ans但在这种情况下,java 编译器需要默认分支(标有 A 的行),否则会失败并出现以下错误:
TestRecordPatter.java:[10,40] switch 表达式未涵盖所有可能的输入值
在第二个开关中,问题是使用var而不是显式类型 forans将开关的返回类型绑定到Object而不是绑定到String。(标有 B 的线)。此外,但这不是 java 编译器问题,IntelliJ 在标记为 C 的行上抱怨,突出显示该var ans部分并说“需要类型 T,但提供了 null”之类的内容。
最后,第三个开关工作正常,但这是“旧”(java 17 很旧,对吧?)的做法。
有人能帮我吗?难道我做错了什么?
编辑:我刚刚下载了 Oracle JDK-19 GA 版本,它也有同样的问题。
编辑2:第二个开关,具有与var第一个开关相同的行为,因此它需要一个默认情况,正如 Holger 所指出的
难道我做错了什么?
是和不是。您正在对枚举和密封类型如何交互(以及常量case标签)进行假设,如果您来自 Haskell,那么这些假设是有意义的,但 Java 尚未赶上。具体来说,枚举的穷举性检查仅限于切换该枚举类型,因此当枚举类型用作密封类型的允许子类型时,枚举值的穷举性尚未被视为穷尽允许的子类型。这是因为常量大小写标签尚未被视为模式,而是以其旧含义对待。将来将会出现彻底混合恒定大小写标签和密封类型的情况(回想一下,这仍然是预览功能。)
与此同时,以下工作正常:
sealed interface Opt<T> { ... }
record Some<T>(T t) implements Opt<T> { }
record None<T>() implements Opt<T> { }
Run Code Online (Sandbox Code Playgroud)
我明白你为什么选择枚举,并且在时间成熟的情况下,这一举措会起作用,但目前还没有。