【问题标题】:Is there a real reason to use Optional.of()?有使用 Optional.of() 的真正理由吗?
【发布时间】:2016-12-16 09:49:50
【问题描述】:

我已经读过here为什么要使用Optional.of()而不是Optional.ofNullable(),但答案根本不让我满意,所以我问的略有不同:

如果您确定您的方法不会返回null,那么为什么要使用Optional?据我所知,它或多或少的唯一目的是提醒“方法的用户”,他可能不得不处理null-values。如果他不必处理null-values,他为什么要打扰Optional

我问,因为我最近让我的服务层返回 Optionals 而不是 nulls(在某些情况下)。我使用了Optional.of(),当它抛出一个 NullPointer 时非常困惑。

我所做的一个示例:

Optional valueFromDB = getUserById("12");
User user = valueFromDB.get(); 

.....

public Optional<User> getUserById(String id) {
  //...
  return Optional.of(userRepository.findOne(id)); // NullPointerException!
}

如果 null 是不可能的,我不明白为什么要把它包装在 Optional 中。链接答案中的家伙说:“好吧,如果发生 NullPointer,它会立即发生!”但我真的想要吗?如果Optional 的唯一目的是提醒获得这样一个对象的程序员,记住null(他必须打开它),我为什么要在包装时拥有NullPointerException


编辑:我需要编辑问题,因为它被标记为重复,即使我已经从一开始就链接了所述问题。我也解释了为什么答案不让我满意,但现在我需要用解释来编辑我的文本。 但这里是我想问的一些附录,因为我得到了 5 个答案,每个人都回答了不同的情况,但没有一个完全涵盖我在这里试图问的问题:

是否有原因, Optional.of(null) 是不可能的,他们专门为 null 情况添加了 Optional.ofNullable() ?

使用流不应该是我的实现想法的问题。 从你的回答中我得到了很多见解,谢谢。但就我所知/阅读/理解而言,真正的问题直到现在还没有得到回答。 也许我应该问:“如果我们删除 Optional.of() 方法并在 Java 9 中只允许 Optional.ofNullable() 怎么办,除了向后兼容会不会有任何问题?”

【问题讨论】:

  • Optional 的唯一目的是明确指出可能没有结果。如果使用得当,您不需要进行null 检查,您可以进行user.ifPresent(doAMethod()) 或可以在流和其他JDK8 API 中使用它而无需检查null 元素。因此,如果使用得当,它可以减少代码中的空值检查量。
  • @M.Deinum: ifPresent 基本上是一个空检查。 :P 它看起来更好,使用更方便。虽然我得到了流的东西,但这与问题本身无关。我没有质疑 Optionals,我确实质疑 Optional.of() 是否有用。抱歉,如果不清楚。
  • 如果您的方法不打算返回 null,一方面我同意您不想返回 Optional。另一方面,如果有一天您要返回的值错误地为空,您确实希望得到通知。我会使用一个很好的旧 assert 声明。

标签: java nullpointerexception java-8 optional


【解决方案1】:

您将 API 设计原理与特定实现代码中的知识混为一谈。一个方法声明返回一个Optional 是完全可能的,因为该值可能不存在,而在方法中的某个代码位置,它肯定存在。即

String content;
public Optional<String> firstMatch(String pattern) {
    Matcher m = Pattern.compile(pattern).matcher(content);
    return m.find()? Optional.of(m.group()): Optional.empty();
}

此方法的返回类型表示可能不存在的String,而在创建Optional 实例的代码位置,可以知道该值是否存在。这与在此处检测 null 值无关。

同样,在 Stream API 方法 findFirst()findAny() 中,将在某一时刻知道是否存在匹配元素,同时支持在匹配 null 的情况下将其存在转换为不存在element 明确不受支持,应该引发NullPointerExceptionper specification。因此,Optional.of 将用于返回匹配元素,您可以在使用Stream.of((Object)null) .findAny(); 时在堆栈跟踪中轻松识别

【讨论】:

  • 另一个例子见here
【解决方案2】:

当您知道value 不能为空时使用Optional.of(value) 的另一个原因是,如果您想对该Optional 执行额外的过滤操作。

例如:

public static long getPageSizeFrom(HttpServletRequest request) {
    return Optional.of(request.getParameter("pageSize"))
                   .filter(StringUtils::isNumeric)
                   .map(Long::valueOf)
                   .filter(page::hasPageSize)
                   .orElse(page::getDefaultPageSize)
}

【讨论】:

    【解决方案3】:

    我认为你的观点是正确的,如果你确定你总是有一个返回值,你不应该使用 Optional。

    但是你的方法不确定,它总是返回一个值!

    考虑调用 getUserById(-1)。 (通常)没有具有此 ID 的用户,您的 userRepository 将返回 null

    所以在这种情况下你应该使用 Optional.ofNullable。

    https://docs.oracle.com/javase/8/docs/api/java/util/Optional.html#ofNullable-T-

    【讨论】:

    • 是的,但问题是,为什么Optional.of() 存在。
    • @codepleb,没错!我有同样的问题。所以我尝试用Optional.of() 运行一行代码。它在这一行本身引发异常。所以我明白,如果一个字段不应该为 NULL,那么用Optional.of() 声明它。如果它为 null,则在此声明中引发异常,而不是在此对象上的任何其他方法调用中引发异常。这会通知开发人员该对象应该具有一个值,与其进一步使用无关。在正常申报的情况下,操作时会得到一个NPE。编辑:大声笑,注意到我评论还为时过早:D
    【解决方案4】:

    Optional 是从函数式编程语言中引入并被 OO 和程序程序员 without much background explanation... 引起了很多痛苦和绞痛的东西之一。

    首先,快速链接到一篇博文(不是我写的),这有助于澄清这一点:The Design of Optional

    Optional 与 Haskell Maybe 等函数式编程类型有关。由于强类型在函数式编程中的工作方式,该语言的程序员会使用 Maybe 来表示值可以是Something 或Nothing。在这里,Something 和 Nothing 实际上是不同的类型。任何需要 Maybe has 中的值来处理两者的东西 - 如果不处理两者,代码根本不会编译。

    将该场景与基于 C 的面向对象语言(Java、C#、C++ 等)中的典型情况进行比较,其中对象可以具有值或为空。如果一个方法需要将 null 参数作为边缘情况处理,您需要显式编写该代码 - 作为我们都是懒惰的程序员,我们通常不会费心去做。

    想象一下,如果代码无法编译,除非 总是 明确处理空情况,否则编码会是什么样子。这与在函数式语言中使用 Maybe 时发生的情况非常接近。

    当我们从函数式编程中提取语言特性时,编译器的行为方式始终如一,我们的编码方式也始终如一……您会看到发生了脱节。

    另外,Optional 可以用作 null 的简单替代。因为它看起来很熟悉,而且是新的,magpie developers 倾向于使用它来替代以前会发生空检查的情况。但是,最后,foo.isPresent() 真的 so 与 foo != null 不同。如果这是唯一的区别,那就没有意义了。

    让我们甚至不开始了解 Optional 如何成为 Java 中自动装箱和拆箱的替代品。

    现在,回到您关于 Java 中 Optional 的特定 API 的具体问题,比较 ofNullable() 与 of(),我能得出的最好结论是您可能不希望在典型代码中使用它们.它们主要用于stream()操作的终端。您可以查看 Optional.of() 与 Optional.ofNullable() 的代码,并亲自了解唯一的区别是 ofNullable 检查值是否为 null 并针对这种情况进行安排。

    我已经厌倦了在 Java 中使用 Optional 并没有看到很多好处,除非我必须使用 Java 8 流。 Some 会说使用 Optional 作为非流使用类型的主要好处是指定特定参数是可选的 - 也就是说,如果逻辑存在与不存在,则逻辑采用不同的路线。同样,您可以简单地使用 null。但我想说,与 Optional 相关的心理包袱意味着,对于本应更冗长的代码的每一步,您都在向后退几步,要求人们理解 Optional(在这种特定情况下)几乎完全是装饰性的。对于您描述的情况,我可能会重新使用空值和空值检查。

    【讨论】:

    • 感谢您的诚实意见。使用它们的最大原因(对我来说)是提醒开发人员,一个值可能是空的。静态代码分析基本可以做到。
    【解决方案5】:

    Angelika Langer 说Optional.ofNullable 只是一种便利方法,从Optional 调用其他两个静态方法。它被实现为:

    return value == null ? empty() : of(value) ;
    

    她还说 Optional.ofNullable 最近被添加到 API 中。

    这是她的德语文本:http://www.angelikalanger.com/Articles/EffectiveJava/80.Java8.Optional-Result/80.Java8.Optional-Result.html

    所以我只会在 null 是错误时使用Optional.of,这应该尽早发现。这是 Tagir Valeev 所说的: Why use Optional.of over Optional.ofNullable?

    【讨论】:

      【解决方案6】:

      实际的答案是:在大多数情况下,不会。正如您所提到的,如果使用 Optional 的全部意义在于不知道一个值是否可以返回 null,并且您想在某些 API 中使其明确,那么 .of() 可以抛出 null 异常的事实没有任何意义。我总是使用 ofNullable。

      我能想到的唯一情况是,如果您有一个返回 Optional 的方法(以明确这种空值的可能性),并且该方法在某些情况下具有默认/备用值,您将返回一个“默认值" 可选,使用 .of()。

      public Optional<String> getSomeNullableValue() {
         if (defaultSituationApplies()) { return Optional.of("default value"); }
         else {
            String value = tryToGetValueFromNetworkOrNull();
            return Optional.ofNullable(value);
         }
      }
      

      再一次,有人可能会质疑在这种情况下您是否可以在 null 的情况下返回此默认值。

      抛开形而上学的讨论,恕我直言,如果您使用 Optionals,并希望它们有意义且不引发异常,请使用 ofNullable()。

      【讨论】:

        【解决方案7】:

        我同意Optional.of 是违反直觉的,对于大多数用例,您会希望使用Optional.ofNullable,但Optional.of 有多种用途:

        1. 如果值为null,则显式抛出NullPointerException。在这种情况下,Optional.of 充当 Guard。
        2. 当值根本不能是null。例如,像Optional.of("Hello world"!) 这样的常量。这是编程美学的事情。 Optional.ofNullable("Hello world!") 看起来很奇怪。
        3. 将非空值转换为Optional 以进一步与mapfilter 链接。这更像是一个编程方便的事情。就像Optional.stream() 的存在是将Optional 转换为Stream 以进行进一步链接。

        【讨论】:

          【解决方案8】:

          “如果我们去掉 Optional.of() 方法,只在 Java 9 中允许 Optional.ofNullable(),除了向后兼容会不会有什么问题?”

          是的,当然会有兼容性问题。使用 Optional.of 的代码太多了。

          我同意你的普遍看法:Optional.of 正在做太多(包装值空检查)。对于空检查,我们已经有了Objects.requireNonNull,它可以方便地重载以接受描述性文本。

          Optional.ofOptional.ofNullable 应该被丢弃以支持为用户提供的构造函数:

          return new Optional<>(value);
          

          对于空检查,这就足够了:

          return new Optional<>(Objects.requireNonNull(value, "cannot be null!"));
          

          【讨论】:

          • 我不同意。根据定义,空的可选项不等同于 null;它只是发生使用 null 作为内部实现细节。 Guava 的Optional 有一个非常相似的接口,但在为空时的内部表示完全不同。暴露构造函数会不必要地泄漏实现并模糊 null 和 empty 之间的界限。
          • @shmosel 如何暴露构造函数泄漏实现?
          • 这意味着 null 是可选的有效值,它限制了像 Guava 那样支持多种实现的能力。
          • @shmosel It implies that null is a valid value for an optional 好吧,Optional.ofNullable 已经在这样做了,所以“秘密”已经出来了。 “限制支持多种实现的能力”与“泄露实现”无关。
          • 不,ofNullable() 是一个工厂方法,可以将 null 转换 null 为空。是的,禁止子类会泄露客户不需要知道的类型层次结构信息。
          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2016-06-16
          • 1970-01-01
          • 2012-01-03
          • 1970-01-01
          • 2020-06-26
          相关资源
          最近更新 更多