我已经使用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的主要设计目标是为函数返回值提供一种方法,以指示没有返回值。请看这个讨论。这允许调用方继续一连串流畅的方法调用。
这与OP问题中的用例#1最接近。尽管,缺少值是比null更精确的表述,因为像IntStream。findFirst永远不能返回null。
对于用例#2,将一个可选参数传递给一个方法,这可以实现,但相当笨拙。假设您有一个方法,它接受一个字符串,后面跟着一个可选的第二个字符串。接受Optional作为第二个参数将导致如下代码:
foo("bar", Optional.of("baz"));
foo("bar", Optional.empty());
即使接受null也更好:
foo("bar", "baz");
foo("bar", null);
最好的方法是有一个重载方法,接受单个字符串参数,并为第二个参数提供默认值:
foo("bar", "baz");
foo("bar");
这确实有局限性,但它比上面任何一种都要好得多。
用例#3和#4,在类字段或数据结构中使用Optional,被认为是对API的滥用。首先,它违背了上文所述的Optional的主要设计目标。其次,它不会增加任何价值。
处理Optional中缺少值的方法有三种:提供替代值、调用函数提供替代值或抛出异常。如果你要存储到一个字段中,你会在初始化或赋值时这样做。如果您正在向列表中添加值,如OP所述,您可以选择不添加值,从而“平坦化”缺少的值。
我相信有人会想出一些人为的例子,他们确实想在字段或集合中存储Optional,但通常情况下,最好避免这样做。
Optional的主要设计目标是为函数返回值提供一种方法,以指示没有返回值。请看这个讨论。这允许调用方继续一连串流畅的方法调用。
这与OP问题中的用例#1最接近。尽管,缺少值是比null更精确的表述,因为像IntStream。findFirst永远不能返回null。
对于用例#2,将一个可选参数传递给一个方法,这可以实现,但相当笨拙。假设您有一个方法,它接受一个字符串,后面跟着一个可选的第二个字符串。接受Optional作为第二个参数将导致如下代码:
foo("bar", Optional.of("baz"));
foo("bar", Optional.empty());
即使接受null也更好:
foo("bar", "baz");
foo("bar", null);
最好的方法是有一个重载方法,接受单个字符串参数,并为第二个参数提供默认值:
foo("bar", "baz");
foo("bar");
这确实有局限性,但它比上面任何一种都要好得多。
用例#3和#4,在类字段或数据结构中使用Optional,被认为是对API的滥用。首先,它违背了上文所述的Optional的主要设计目标。其次,它不会增加任何价值。
处理Optional中缺少值的方法有三种:提供替代值、调用函数提供替代值或抛出异常。如果你要存储到一个字段中,你会在初始化或赋值时这样做。如果您正在向列表中添加值,如OP所述,您可以选择不添加值,从而“平坦化”缺少的值。
我相信有人会想出一些人为的例子,他们确实想在字段或集合中存储Optional,但通常情况下,最好避免这样做。
在java中,除非你沉迷于函数式编程,否则不要使用它们。
它们没有作为方法参数的位置(我保证有一天会有人传递给你一个空的可选参数,而不仅仅是一个空的可选参数)。
它们对返回值有意义,但它们会让客户端类继续延伸行为构建链。
FP和链在像java这样的命令式语言中几乎没有位置,因为它使调试变得非常困难,而不仅仅是阅读。当你走到这一行时,你无法知道程序的状态和意图;你必须一步一步地找出它(尽管有步骤过滤器,但通常不是你的代码和许多堆栈帧深),你必须添加大量断点,以确保它可以停止在你添加的code/lambda中,而不是简单地走if/else/call琐碎的行。
如果你想要函数式编程,选择java以外的语言,并希望你有调试它的工具。