如果编译器在期望 Optional<Object> 作为参数时解析空值,这会是个好主意吗?

Would it be a good idea if compiler resolved nulls when Optional<Object> is expected as argument?

这显然非常有用,以至于我开始认为我缺少避免它的理由,因为我确信 Oracle 会这样做。对我来说,这将是 Optional 上最有价值的功能。

public class TestOptionals{
    public static void main(String[] args) {
        test(null);
    }

    public static void test(Optional<Object> optional){
        System.out.println(optional.orElse(new DefaultObject()));
    }
}

(抛出 NullPointerException)

如果没有该功能,我认为使用 Optional 作为参数太冗长了。 我更喜欢简单的 Object optional 签名和 通过 if (null = optional) 检查创建对象 Optional 以供稍后比较。如果这不能帮助您检查 null

,那么它就没有价值

在所有 Java 邮件列表中对 Optional 进行了 HUGE 讨论,其中包含数百条消息。在网络上搜索

site:mail.openjdk.java.net optional

并且您将获得许多链接。当然,我什至不希望总结所有提出的问题。有很多争议,关于 应该向平台添加多少 "optionality" 存在相当广泛的意见。有些人认为根本不应该添加库解决方案;有些人认为没有语言支持的库解决方案是无用的;有些人认为库解决方案是可以的,但对于其中应该包含什么存在大量争论;等等。请参阅 lambda-dev 邮件列表中的 message from Brian Goetz 以了解一些观点。

lambda 团队做出的一个务实决定是任何类似可选的功能都不能涉及任何语言更改。语言和编译器团队已经忙于处理 lambda 和默认方法。这些当然是主要优先事项。实际上,选择要么将 Optional 添加为库 class,要么根本不添加。

当然,人们知道支持选项类型的其他语言的类型系统。这将是对 Java 类型系统的重大改变。事实上,在过去 20 年的大部分时间里,引用类型都可以为 null,并且只有一个未类型化的 null 值。改变这一点是一项艰巨的任务。甚至可能无法以兼容的方式执行此操作。我不是这方面的专家,但大多数此类讨论往往很快就会陷入困境。

一个可能更容易处理的小改动( 也提到了)是将引用类型和 Optional 之间的关系视为一种装箱,然后引入对 autoboxing/autounboxing 已经在该语言中了。

这已经有点问题了。当在 Java 5 中添加自动(取消)装箱时,它使大量情况变得更好,但它给语言增加了很多粗糙的边缘。例如,通过自动拆箱,现在可以使用 <> 来比较装箱的 Integer 对象的值。不幸的是,使用 == 仍然比较引用而不是值!装箱也使重载决议变得更加复杂;它是当今语言中最复杂的领域之一。

现在让我们考虑引用类型和 Optional 类型之间的自动(取消)装箱。这会让你做:

Optional<String> os1 = "foo";
Optional<String> os2 = null;

在此代码中,os1 将以装箱字符串值结束,而 os2 将以空可选结束。到目前为止,一切都很好。现在反过来:

String s1 = os1;
String s2 = os2;

现在 s1 将得到未装箱的字符串 "foo",我猜 s2 将被拆箱为 null。但是 Optional 的目的是让这种拆箱变得明确,这样程序员就可以决定如何处理一个空的 Optional,而不是让它变成 null

嗯,所以也许我们只对 Optional 进行自动装箱,而不是自动拆箱。让我们 return 到 OP 的用例:

public static void main(String[] args) {
    test(null);
}

public static void test(Optional<Object> optional) {
    System.out.println(optional.orElse(new DefaultObject()));
}

如果你真的想用Optional,你可以手动把它框起来一行:

public static void test(Object arg) {
    Optional<Object> optional = Optional.ofNullable(arg);
    System.out.println(optional.orElse(new DefaultObject()));
}

显然,如果您不必编写此代码可能会更好,但是要节省这行代码将需要大量的 language/compiler 工作和兼容性风险。真的值得吗?

似乎发生的事情是,这将允许调用者传递 null 以便对被调用者具有某些特定含义,例如 "use the default object" 。在小例子中,这看起来不错,但总的来说,将语义加载到 null 上似乎越来越不是一个好主意。因此,这是不为 null 的装箱添加特定语言支持的另一个原因。 Optional.ofNullable() 方法主要用于弥合使用 null 的代码和使用 Optional.

的代码之间的差距

如果您致力于使用可选 class,请参阅其他答案。

另一方面,我将您的问题解释为,"Would it be a good idea to avoid the syntactic overhead of using Optional while still obtaining a guarantee of no null pointer exceptions in your code?" 这个问题的答案是肯定的。幸运的是,Java 有一个功能,类型注释,可以实现这一点。它不需要使用 Optional class.

您可以获得相同的编译时保证,无需向您的代码添加 Optional,同时保持与现有代码的向后兼容性。

  1. 注释可能为 @Nullable 类型的空引用 注释。
  2. 运行 一个编译器插件,例如 Checker Framework's Nullness Checker.

如果插件没有发出错误,那么您就知道您的代码总是在需要的地方检查 null,因此您的代码永远不会在 运行 时间发出空指针异常。

该插件处理@immibis 等提到的特殊情况,因此您的代码比使用 Optional 的代码要简洁得多。该插件与普通 Java 代码兼容,不需要像 Optional 那样使用 Java 8。 Google.

等公司每天都在使用它

请注意,此方法要求您向编译器提供命令行参数,以告知 运行 插件。另请注意,此方法不与 Optional 集成;这是另一种方法。