我已经使用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>>
添加任何东西-特别是因为一个人可以使用过滤器()删除空值等,但在集合中有任何可选的好用途吗?
有我错过的案子吗?
我认为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的设计目标,Stuart Marks的回答很好地总结了这一点,但我仍然相信它们的有效性。
到处使用Optional
在一般情况下
我写了一篇关于使用Optional的完整博客文章,但它基本上可以归结为:
在设计类时,尽可能避免可选性
在所有其余的情况下,默认应该使用Optional而不是null
可能会有例外:
局部变量
返回值和参数给私有方法
性能关键代码块(不用猜测,使用分析器)
前两个异常可以减少在Optional中包装和解包装引用的开销。它们的选择使得null对象永远不能合法地将边界从一个实例传递到另一个实例。
注意,这几乎不允许集合中出现可选项,这几乎和null一样糟糕。千万别这么做。;)
关于你的问题
是的。
如果没有重载选项,则是。
如果没有其他方法(子类化、装饰……),可以。
请不!
优势
这样做可以减少代码库中null的存在,但并不能根除它们。但这还不是重点。还有其他重要的优势:
澄清意图
使用Optional清楚地表示变量是可选的。任何代码的读者或API的消费者都会被这样的事实所迷惑,即可能没有任何内容,在访问值之前必须进行检查。
消除不确定性
如果没有Optional,空值的含义是不清楚的。它可以是状态的合法表示(参见Map.get),也可以是缺少初始化或初始化失败等实现错误。
随着Optional的持续使用,这种情况发生了巨大的变化。在这里,null的出现已经表明存在bug。(因为如果允许缺少该值,则会使用Optional。)这使得调试空指针异常变得容易得多,因为这个空指针的含义问题已经得到了回答。
更多空检查
既然没有任何东西可以再为空,这就可以在任何地方强制执行。无论是使用注释、断言还是普通检查,您都不必考虑这个参数或那个返回类型是否可以为空。它不能!
缺点
当然,没有什么灵丹妙药……
性能
将值(尤其是原语)包装到额外的实例中会降低性能。在紧密循环中,这可能会变得明显,甚至更糟。
请注意,编译器可能能够规避可选项的短生命周期的额外引用。在Java 10中,值类型可能会进一步减少或消除惩罚。
序列化
可选的是不可序列化的,但解决方案不是太复杂。
不变性
由于Java中泛型类型的不变性,当实际值类型被推入泛型类型参数时,某些操作变得很麻烦。这里给出了一个例子(参见“参数多态”)。