Java流。只有一次

时间:2017-09-06 12:15:46

标签: java java-8

在我的过滤器为真后,有没有办法让我的流只迭代一次?

示例:

list.stream()
    .filter(ele -> ele.isBlue())
    .map(Element::getSomething)
    .collect(toList());

说我的列表中有很多元素,但只有一个是蓝色的。我知道只有一个是蓝色的,但我不知道它在哪里。为了论证,让我们说isBlue()是一个缓慢的方法,所以我想在它碰到一次时停止。

3 个答案:

答案 0 :(得分:7)

如果您只查找一个元素,而不是collect()使用findFirst() / findAny()

Optional<Something> s = list.stream()
    .filter(ele -> ele.isBlue())
    .map(Element::getSomething)
    .findAny();

然后您可以获得包含单个蓝色元素的Optional或空Optional

简单流中的findFirst()findAny()之间没有区别,只有在涉及并行性时(findFirst()确定性地返回第一个元素,findAny()将返回它找到的任何一个合适的元素。

答案 1 :(得分:5)

您仍可collect,但limit

list.stream()
   .filter(ele -> ele.isBlue())
   .map(Element::getSomething)
   .limit(1)
   .collect(toList());

答案 2 :(得分:3)

值得理解的是,流管道是由最后一步驱动的,终止操作

没有想到一个流生产商将物品沿着传送带推入等待的消费者,而是想到拉动物品的终止操作 - 生产者在被问到时会添加新物品。

在您的示例中,终止操作是collect(collector) - 这将从上一步骤中拉出项目,直到不再有,将每个元素提交给收集器。上一步是map(),但它可以按需运行 - 它只会从之前的步骤中提取项目 - filter() - 当collect()要求另一项时。

findFirst()是另一个终止操作。它向上一步询问一个项目 - 流中的第一个项目。因此,如果我们将您的示例更改为...

list.stream()
   .filter(ele -> ele.isBlue())
   .map(Element::getSomething)
   .findFirst(toList());

... findFirst()管道步骤将从map()步骤中读取一次。如果它获得了一个项目,它将返回Optional.of(item)

map()反过来会从filter()读取一次。 filter()将重复读取流,直到isBlue()为真,然后返回。

如果filter()到达其输入流的末尾而未找到匹配项,则它将指示流结束。这将沿着管道向下传播,findFirst()将注意到流末尾,并返回Optional.empty()

还有findAny(),它将返回任意匹配项。如果管道的一部分被并行化,这可能会更快地返回 - 或者当有一个顺序敏感的步骤阻止它时,它可能允许管道并行化。

查看Stream Javadoc以查看所有终止操作。