是否有使用Optional.of()的真正原因?

时间:2016-12-16 09:49:50

标签: java nullpointerexception java-8 optional

我已阅读here为什么Optional.of()应该在Optional.ofNullable()上使用,但答案根本不符合我的要求,所以我要求略有不同:

如果您确定自己的方法没有返回null,为什么要使用Optional?据我所知,它或多或少的唯一目的是提醒“方法的用户”,他可能必须处理null - 值。如果他不需要处理null - 值,他为什么要被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()怎么办?除了向后兼容性之外会不会有任何问题?”

9 个答案:

答案 0 :(得分:11)

您正在将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元素明确不受支持,并且应该引发NullPointerExceptionper specification。因此,Optional.of将用于返回匹配元素,使用Stream.of((Object)null) .findAny();

时,您可以在堆栈跟踪中轻松识别该匹配元素

答案 1 :(得分:7)

当您知道Optional.of(value)不能为空时,使用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)
}

答案 2 :(得分:1)

我认为您认为如果您确定始终具有返回值,则不应使用“可选”。

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

想一想对 getUserById(-1)的调用。 (通常)没有具有此ID的用户,并且您的 userRepository 将返回 null

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

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

答案 3 :(得分:1)

Angelika Langer说,Optional.ofNullable只是一种便利方法,将另一种方法称为Optional的静态方法。它实现为:

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

她还说最近在API中添加了Optional.ofNullable

以下是她的德语文本: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?

答案 4 :(得分:1)

可选是从函数式编程语言导入并转移到OO和程序编程人员without much background explanation的那些内容之一......这已经造成了很大的痛苦和扭曲。 / p>

首先,快速链接到博客文章(不是我),这有助于清除空气:The Design of Optional

可选与Haskell Maybe等函数式编程类型相关。由于强类型在函数式编程中的运行方式,该语言的程序员会使用Maybe来表示值可以是Something,也可以是Nothing。在这里,Something和Nothing实际上是不同的类型。任何需要Maybe 中的值的东西都有来处理这两个 - 如果它不能处理这两个代码,它就会简单地编译。

将该场景与基于C的面向对象语言(Java,C#,C ++等)中的典型情况进行比较,其中对象可以具有值,也可以为null。如果一个方法需要处理null参数作为边缘情况,你需要明确地编写那些代码 - 并且作为我们所有人都是懒惰的程序员,它就像我们不经常烦恼一样。

想象一下,如果代码无法编译,那将是什么样的编码,除非总是显式处理空案​​例。这与在函数式语言中使用Maybe时发生的情况非常接近。

当我们从函数式编程中提取语言特性时,编译器的行为方式与它始终具有的方式相同,并且我们按照我们始终拥有的方式进行编码......您可以看到发生了断开连接。

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

让我们开始看看Optional如何成为Java中自动装箱和拆箱的替身。

现在,回到你关于Java中Optional的特定API的具体问题,比较ofNullable()和(),我可以解决的最好的问题是你可能不会在典型代码。它们主要用于stream()操作的终端。您可以查看Optional.of()与Optional.ofNullable()的代码,并自己查看唯一的区别是ofNullable检查该值是否为null并为该情况安排事情。

我厌倦的眼睛并没有看到在Java中使用Optional有很多好处,除非我使用的是Java 8流,而且我必须这样做。 Some会说使用Optional作为非流使用类型的主要好处是指定特定参数是可选的 - 也就是说,逻辑采用不同的路径,如果它与那里相对不在那里。再次,你可以简单地使用null。但我要说的是,与Optional相关的心理包袱意味着,对于所谓的更详细的代码的每个前进步骤,你需要向后退一步,要求人们理解Optional(在这个特定情况下)几乎完全是装饰性的。对于您描述的情况,我可能会回到使用空值和空值检查。

答案 5 :(得分:0)

实际的答案是:在大多数情况下,不是。如您所提到的,如果使用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);
   }
}

然后,有人可以质疑在这种情况下是否可以返回默认值(如果为空)。

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

答案 6 :(得分:0)

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

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

答案 7 :(得分:-1)

  

“如果我们删除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!"));

答案 8 :(得分:-1)

Optional.of()当您确定Optional永远不会有一个空对象并且它将包含对象值或者它将为空但不会为空时,应使用

Optional.of()。如果Optional是使用null值创建的,则Optional.of()可以引发NullPointerEception。 Optional.ofNullable()-在对象可能为null的情况下使用。

Optional.of()将返回Optional的对象,不进行空检查。 让我们看一下Optional.of()方法的实习生:

public static <T> Optional<T> of(T value) {
     return new Optional<>(value);
}

Optional.ofNullable()将返回带有空检查的Optional对象。如果此方法将null用作输入,则它将返回空Optional,否则将返回具有指定的当前非null值的Optional 让我们看一下Optional.ofNullable()方法的实习生:

public static <T> Optional<T> ofNullable(T value) {
     return value == null ? empty() : of(value);
}

您可以在以下帖子中了解更多信息: http://onlyfullstack.blogspot.com/2018/12/optional-in-java-8.html