我已经使用Java 8 6个多月了,我对新的API变化非常满意。我仍然不确定的一个领域是什么时候使用Optional。我似乎在想要在任何地方使用它之间摇摆,有些东西可能是空的,而根本没有。

似乎在很多情况下我都可以使用它,但我不确定它是否会增加好处(可读性/零安全性),还是只会导致额外的开销。

所以,我有几个例子,我对社区对Optional是否有益的想法很感兴趣。

1 -当方法可以返回null时,作为一个公共方法返回类型:

public Optional<Foo> findFoo(String id);

2 -当参数可以为空时,作为方法参数:

public Foo doSomething(String id, Optional<Bar> barOptional);

3 -作为bean的可选成员:

public class Book {

  private List<Pages> pages;
  private Optional<Index> index;

}

4 -收集:

总的来说,我不认为:

List<Optional<Foo>>

添加任何东西-特别是因为一个人可以使用过滤器()删除空值等,但在集合中有任何可选的好用途吗?

有我错过的案子吗?


当前回答

似乎Optional只有在Optional中的类型T是int、long、char等基本类型时才有用。对于“真正的”类,这对我来说没有意义,因为你可以使用空值。

我认为它是从这里(或从另一个类似的语言概念)。

Nullable < T >

在c#中,这个Nullable<T>很久以前就被引入到换行值类型中。

其他回答

我不认为Optional是可能返回空值的方法的一般替代品。

基本思想是:一个值的缺失并不意味着它在未来可能是可用的。它是findById(-1)和findById(67)之间的差值。

可选项对于调用者的主要信息是,他可能不指望给定的值,但它可能在某个时间可用。也许它会再次消失,然后再回来一次。这就像一个开/关开关。你可以“选择”打开或关闭灯。但是如果你没有灯可以打开,你就别无选择了。

所以我发现它太乱引入可选的地方,以前可能返回null。我仍然会使用null,但是只在一些受限的地方,比如树的根、惰性初始化和显式查找方法。

下面是一些你可以在Optional<T>实例上执行的方法:

地图 平面地图 或者其他 orElseThrow ifPresentOrElse 获取

以下是你可以在null上执行的所有方法:

(没有)

这实际上是一个苹果和橙子的比较:Optional<T>是一个对象的实际实例(除非它是null…但这可能是一个错误),而null是一个中止的对象。对于null,您所能做的就是检查它实际上是否为空。所以如果你喜欢在对象上使用方法,Optional<T>适合你;如果您喜欢在特殊的字面量上进行分支,那么null是适合您的。

Null不构成。您不能简单地组合一个只能进行分支的值。但是Optional<T>确实作曲。

例如,您可以使用map创建任意长的“如果非空则应用此函数”链。或者,您可以有效地使用ifPresent创建一个命令代码块,如果可选值非空,则使用该可选值。或者你可以通过使用ifPresentOrElse来创建一个“if/else”,如果非空则使用非空可选参数,否则执行其他代码。

在这一点上,我们遇到了我认为语言的真正局限性:对于非常命令式的代码,你必须将它们包装在lambdas中,并将它们传递给方法:

    opt.ifPresentOrElse(
            string -> { // if present...
                // ...
            }, () -> { // or else...
                // ...
            }
    );

这对某些人来说可能不够好,就风格而言。

如果Optional<T>是一个可以进行模式匹配的代数数据类型(这显然是伪代码:

    match (opt) {
        Present(str) => {
            // ...
        }
        Empty =>{
            // ...
        }
    }

总之,总结一下:Optional<T>是一个非常健壮的空或现对象。Null只是一个哨兵值。

主观上忽视了原因

There seems to be a few people who effectively argue that efficiency should determine whether one should use Optional<T> or branch on the null sentinel value. That seems a bit like making hard and fast rules on when to make objects rather than primitives in the general case. I think it’s a bit ridiculous to use that as the starting point for this discussion when you’re already working in a language where it’s idiomatic to make objects left-and-right, top to bottom, all the time (in my opinion).

Oracle教程:

Optional的目的不是替换代码库中的每一个空引用,而是帮助设计更好的api,使用户可以通过读取方法的签名来判断是否需要一个可选值。此外,Optional强制您主动展开Optional以处理缺少值的情况;因此,可以保护代码不受意外空指针异常的影响。

我认为Guava Optional和他们的维基页面说得很好:

Besides the increase in readability that comes from giving null a name, the biggest advantage of Optional is its idiot-proof-ness. It forces you to actively think about the absent case if you want your program to compile at all, since you have to actively unwrap the Optional and address that case. Null makes it disturbingly easy to simply forget things, and though FindBugs helps, we don't think it addresses the issue nearly as well. This is especially relevant when you're returning values that may or may not be "present." You (and others) are far more likely to forget that other.method(a, b) could return a null value than you're likely to forget that a could be null when you're implementing other.method. Returning Optional makes it impossible for callers to forget that case, since they have to unwrap the object themselves for their code to compile. -- (Source: Guava Wiki - Using and Avoiding null - What's the point?)

可选增加了一些开销,但我认为它的明显优势是使其显式化 一个对象可能不存在,它强制程序员处理这种情况。它可以防止有人忘记心爱的人!=空支票。

以2为例,我认为这是更明确的代码:

if(soundcard.isPresent()){
  System.out.println(soundcard.get());
}

if(soundcard != null){
  System.out.println(soundcard);
}

对我来说,可选的更好地抓住了没有声卡的事实。

我对你的观点有2个看法:

public Optional<Foo> findFoo(String id); - I am not sure about this. Maybe I would return a Result<Foo> which might be empty or contain a Foo. It is a similar concept, but not really an Optional. public Foo doSomething(String id, Optional<Bar> barOptional); - I would prefer @Nullable and a findbugs check, as in Peter Lawrey's answer - see also this discussion. Your book example - I am not sure if I would use the Optional internally, that might depend on the complexity. For the "API" of a book, I would use an Optional<Index> getIndex() to explicitly indicate that the book might not have an index. I would not use it in collections, rather not allowing null values in collections

一般来说,我会尽量减少传递null值。(一旦烧…) 我认为有必要找到适当的抽象,并向程序员同事指出某个返回值实际代表什么。

似乎Optional只有在Optional中的类型T是int、long、char等基本类型时才有用。对于“真正的”类,这对我来说没有意义,因为你可以使用空值。

我认为它是从这里(或从另一个类似的语言概念)。

Nullable < T >

在c#中,这个Nullable<T>很久以前就被引入到换行值类型中。