【发布时间】:2019-03-30 15:28:38
【问题描述】:
我有一个返回Optional<Foo> 的方法,如果它存在,我想使用该值来查找Stream<Bar>。
现在我知道我可以做到:
optionalFoo.map(foo->bars(foo)).orElse(Stream.empty());
(为了说明,我使用的是映射函数的完整形式,而不是方法参考。)
使用 Java 9+ 我可以做到这一点:
optionalFoo.stream().flatMap(foo->bars(foo));
但无论哪种方式,额外的步骤似乎都毫无意义。是否有一种映射方法可以简单地将可选项映射到流,或者如果不存在可选项则为空流?然后我可以这样做:
optionalFoo.streamMap(foo->bars(foo));
如果没有这样的方法,为什么不呢?它可以作为一个简单的默认方法添加到Optional。
最后,如果我必须编写自己的实用程序方法,上述哪种方法更有效(看到它们都提供相同的结果):映射到流或空流;或转换为流,然后平面映射到流?我会假设前者更有效,这说明了为什么需要实用方法。 (我们不想到处重新输入.orElse(Stream.empty())。)
对于那些需要具体用例的人,假设有一种方法可以从 DOM 树中返回 HTML <head> 元素:
/**
* Finds the {@code <html><head>} element in the HTML namespace.
* @param document The document tree.
* @return A reference to the {@code <html><head>} element if it exists in the tree.
*/
public static Optional<Element> findHtmlHeadElement(@Nonnull final Document document);
现在另一种方法想要返回所有 HTML <meta> 元素(如果它们存在)。所以它想搜索<head> 元素的子元素,但当然前提是它存在。 (请注意,childElementsByNameNS() 是一种实用方法,可将另一个元素的子元素检索为 Stream<Element>。)
/**
* Finds the {@code <html><head><meta>} elements in an HTML document.
* @param document The document tree.
* @return A stream of {@code <html><head><meta>} elements if they exist in the tree.
*/
public static Stream<Element> htmlHeadMetaElements(@Nonnull final Document document) {
return findHtmlHeadElement(document).map(headElement ->
childElementsByNameNS(headElement, XHTML_NAMESPACE_URI_STRING, ELEMENT_META))
.orElse(Stream.empty());
}
为什么我需要额外丑陋的.orElse(Stream.empty()) 样板?我宁愿有这样的东西:
/**
* Finds the {@code <html><head><meta>} elements in an HTML document.
* @param document The document tree.
* @return A stream of {@code <html><head><meta>} elements if they exist in the tree.
*/
public static Stream<Element> htmlHeadMetaElements(@Nonnull final Document document) {
return findHtmlHeadElement(document).streamMap(headElement ->
childElementsByNameNS(headElement, XHTML_NAMESPACE_URI_STRING, ELEMENT_META));
}
你可能会说“你不能有从Optional 到其他所有类型的特殊映射方法”,但是Optional 和Stream 有一种特殊的关系。事实上,我有点认为Optional 几乎是一个带有零个或一个元素的Stream。事实上,这正是Optional.stream() 所回馈的。所以这真的是对Optional.stream()的补充。
【问题讨论】:
-
那不也取决于
bars(foo)的签名吗?问题的相关细节很重要。例如它将如何处理这种情况Stream.of(optionalFoo) .flatMap(a -> bars(a.orElse(null)))。无论哪种方式,我真的认为不需要这样的streamMap来自可选。可能只是基于意见,但当前示例中的用例也不是很清楚。 -
"这不也取决于
bars(foo)的签名吗?"怎么会这样?当然,参数并不重要——这就是为什么整个东西都被包裹在一个函数 lambda 中。而且返回的流类型无关紧要——这就是为什么我们有带有捕获和通配符的泛型。所以我真的不明白你在说什么。并且说“我认为没有必要”而不说为什么也没有真正澄清太多。您从示例中看到,这将消除对样板文件.orElse(Stream.empty())的需要,对吧?那么您是说您认为不需要删除此样板文件吗? -
@Naman 我添加了具体示例,因此您可以看到这不依赖于
bars(foo)的签名。 -
您的前两个代码示例对我来说似乎完全合理。考虑到你的用例不是很常见,并且考虑到它对可读性没有太大的损害,我不确定我会称之为“样板”。
标签: java java-stream optional