I'm adding this second answer based on a proposed edit by user srborlongan to my other answer. I think the technique proposed was interesting, but it wasn't really suitable as an edit to my answer. Others agreed and the proposed edit was voted down. (I wasn't one of the voters.) The technique has merit, though. It would have been best if srborlongan had posted his/her own answer. This hasn't happened yet, and I didn't want the technique to be lost in the mists of the StackOverflow rejected edit history, so I decided to surface it as a separate answer myself.
基本上,这种技术是以一种巧妙的方式使用一些可选方法来避免必须使用三元操作符(?:)或if/else语句。
我的内联示例可以这样重写:
Optional<Other> result =
things.stream()
.map(this::resolve)
.flatMap(o -> o.map(Stream::of).orElseGet(Stream::empty))
.findFirst();
我的例子中使用了一个helper方法,可以这样重写:
/**
* Turns an Optional<T> into a Stream<T> of length zero or one depending upon
* whether a value is present.
*/
static <T> Stream<T> streamopt(Optional<T> opt) {
return opt.map(Stream::of)
.orElseGet(Stream::empty);
}
Optional<Other> result =
things.stream()
.flatMap(t -> streamopt(resolve(t)))
.findFirst();
评论
让我们直接比较一下原始版本和修改版本:
// original
.flatMap(o -> o.isPresent() ? Stream.of(o.get()) : Stream.empty())
// modified
.flatMap(o -> o.map(Stream::of).orElseGet(Stream::empty))
原来是一个简单的方法:我们得到一个Optional<Other>;如果它有值,则返回包含该值的流,如果它没有值,则返回空流。很简单,也很容易解释。
这种修改很聪明,它的优点是避免了条件语句。(我知道有些人不喜欢三元运算符。如果误用,确实会使代码难以理解。)然而,有时候事情可能太聪明了。修改后的代码还以Optional<Other>开头。然后它调用Optional。映射,定义如下:
如果值存在,则对其应用提供的映射函数,如果结果是非空,则返回描述结果的Optional。否则返回空的Optional。
map(Stream::of)调用返回一个Optional<Stream<Other>>。如果输入Optional中存在一个值,则返回的Optional包含一个包含单个Other结果的流。但如果该值不存在,则结果为空的Optional。
接下来,调用orElseGet(Stream::empty)返回类型为Stream<Other>的值。如果它的输入值是存在的,它得到的值是单个元素Stream<Other>。否则(如果输入值不存在)它返回一个空的Stream<Other>。因此,结果是正确的,与原始条件代码相同。
在对我的回答的评论中,关于被拒绝的编辑,我把这种方法描述为“更简洁,但也更模糊”。我坚持这一点。我花了一段时间才弄清楚它在做什么,也花了一段时间写了上面关于它在做什么的描述。关键的微妙之处在于从Optional<Other>到Optional<Stream<Other>>的转换。一旦你明白了这一点,它就说得通了,但对我来说并不明显。
不过,我承认,随着时间的推移,最初晦涩的东西可能会变成惯用用语。这种技术最终可能成为实践中最好的方法,至少在可选之前是这样。流被添加(如果曾经添加过的话)。
更新:可选的。流已添加到JDK 9。