我已经使用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<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).
我认为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值。(一旦烧…)
我认为有必要找到适当的抽象,并向程序员同事指出某个返回值实际代表什么。