Java 19 模式匹配编译错误:“switch 语句未涵盖所有可能的输入值”

cla*_*lay 10 java pattern-matching switch-statement

使用 Brian Goetz 的文章:https ://www.infoq.com/articles/data-oriented-programming-java/

sealed interface Opt<T> { 
    record Some<T>(T value) implements Opt<T> { }
    record None<T>() implements Opt<T> { }
}
Run Code Online (Sandbox Code Playgroud)

这将按预期编译并运行。详尽的模式匹配工作原理:

Opt<String> optValue = doCalc(value);
switch (optValue) {
  case Opt.Some<String> some -> System.out.printf("got string: %s%n", some.value());
  case Opt.None<String> none -> System.out.printf("got none%n");
};
Run Code Online (Sandbox Code Playgroud)

我使用新的记录模式预览功能的这种变体打破了详尽的模式匹配,如果不添加默认的 case 语句,则无法编译:

Opt<String> optValue = doCalc(value);
switch (optValue) {
    case Opt.Some<String>(String v) -> System.out.printf("got string: %s%n", v);
    case Opt.None<String> none -> System.out.printf("got none%n");
};
Run Code Online (Sandbox Code Playgroud)

使用OpenJDK Runtime Environment (build 19-ea+32-2220),我得到编译错误:the switch statement does not cover all possible input values

当我添加默认的 case 语句时,程序可以工作,但我没有得到详尽的模式匹配。

如果我删除记录模式匹配,程序就可以工作。

如果我创建一个不带泛型的变体,使用密封类、详尽的模式匹配和记录模式,它就可以工作。

然而,记录模式、泛型和详尽模式匹配的组合似乎不起作用。

Pan*_*kos 5

JDK 19现在仅提供早期访问版本。

我想我已经在这个问题中找到了重要的部分我想我已经在J​​EPS 427 文档

模式匹配(第三次预览)的进度也可以从也可以从这里

根据下面的 JEPS 示例,我希望这能起作用,所以我认为您应该首先等待第一个JDK 19 版本的普遍可用性,然后重试。如果它仍然不起作用,那么我认为你应该继续并将其报告为错误。

当允许的直接子类仅实现(通用)密封超类的特定参数化时,需要额外小心。例如:

sealed interface I<T> permits A, B {}
final class A<X> implements I<String> {}
final class B<Y> implements I<Y> {}

static int testGenericSealedExhaustive(I<Integer> i) {
    return switch (i) {
        // Exhaustive as no A case possible!
        case B<Integer> bi -> 42;
    }
}
Run Code Online (Sandbox Code Playgroud)

I 唯一允许的子类是 A 和 B,但编译器可以检测到 switch 块只需要覆盖类 B 即可穷举,因为选择器表达式是类型 I。

我也认为@Kayaman的评论不是这种情况,因为文档中明确说明了如何处理这种情况才能安全。

为了防止不兼容的单独编译,在切换密封类的情况下,其中 switch 块是详尽的并且不存在全部匹配的情况,编译器会自动添加一个默认标签,其代码会抛出 IncompleteClassChangeError。只有改变密封接口并且不重新编译开关代码时才会到达该标签。实际上,编译器会为您强化代码。


cla*_*lay 3

这是 Java 19 中的一个已知错误。Brian Goetz 本人在 amber-dev 邮件列表上证实了这一点。

更新:这个问题在 Java 20 中已完全修复。