在 switch 表达式中尝试记录模式时出现 Java 19 编译器问题

标签 java pattern-matching record java-19

我从这里下载了 JDK19 的候选发布版 https://jdk.java.net/19/尝试使用那里实现的新记录模式,但我遇到了一些问题。在我的测试中,我写了一个基于密封接口(interface)加记录的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;
        }
    }
}

第一个 switch 表达式使用记录解构来使用 ans 变量的显式类型从 Some 变体中获取值,但在这种情况下,java 编译器需要默认分支(标记为A) 否则失败并出现以下错误:

TestRecordPatter.java:[10,40] the switch expression does not cover all possible input values

在第二个开关中,问题是使用 var 而不是 ans 的显式类型会将开关的返回类型绑定(bind)到 Object而不是 String。 (标有 B 的行)。此外,但这不是 Java 编译器问题,IntelliJ 在标记为 C 的行上提示,突出显示 var ans 部分并说“需要类型 T 但提供了 null”之类的话。

最后,第三个开关工作正常,但这是“旧的”(java 17 是旧的,对吧?)方式。

有人可以帮助我吗?我做错了什么吗?

编辑:我刚刚下载了 Oracle JDK-19 GA 版本,它有同样的问题。

编辑 2:第二个开关,带有 var 的开关与第一个开关具有相同的行为,因此它需要一个默认情况,正如 Holger 所指出的那样

最佳答案

Am I doing something wrong?

是也不是。您正在假设枚举和密封类型如何交互(以及常量 case 标签),如果您来自 Haskell,这些假设是有意义的,但 Java 尚未 catch 。具体来说,枚举的穷尽检查仅限于切换该枚举类型,因此当枚举类型用作密封类型的允许子类型时,枚举值的穷举尚未被视为穷尽允许的子类型。这是因为常量大小写标签尚未被视为模式,而是按照它们的旧含义处理。在穷举中混合常量大小写标签和密封类型是将来会出现的事情(回想一下这仍然是一个预览功能。)

与此同时,以下工作正常:

sealed interface Opt<T> { ... }

record Some<T>(T t) implements Opt<T> { }
record None<T>() implements Opt<T> { }

我明白您为什么要使用枚举,并且在适当的时候该举措会奏效,但现在还没有。

关于在 switch 表达式中尝试记录模式时出现 Java 19 编译器问题,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/73787918/

相关文章:

java - 如何从同一目录中存在的 JAR 文件运行或调用 exe 文件?

java - 如何以编程方式向分区/系统写入内容?

java - 删除 Java 字符串中给定模式的表行

f# - 如何在F#中初始化相互递归记录

java - 使用接口(interface)在 fragment 之间传递消息

java - spring 3.0强制单例bean

pattern-matching - 将切片模式与字符串切片一起使用

c# - 识别最频繁的模式。 ¿计数标准?

Java录制/混合两个音频流

c - 从线性列表中删除记录的问题 (C)