在我的過濾器爲真後,有沒有辦法讓我的數據流僅迭代一次?Java流。只有一次
例子:
list.stream()
.filter(ele -> ele.isBlue())
.map(Element::getSomething)
.collect(toList());
說我有我的列表中的許多元素,但只有一個是藍色的。我知道只有一個是藍色的,但我不知道它在哪裏。爲了討論起見,我們可以說isBlue()是一個很慢的方法,所以我想在它碰到一次時停止。
在我的過濾器爲真後,有沒有辦法讓我的數據流僅迭代一次?Java流。只有一次
例子:
list.stream()
.filter(ele -> ele.isBlue())
.map(Element::getSomething)
.collect(toList());
說我有我的列表中的許多元素,但只有一個是藍色的。我知道只有一個是藍色的,但我不知道它在哪裏。爲了討論起見,我們可以說isBlue()是一個很慢的方法,所以我想在它碰到一次時停止。
如果您正在尋找只有一個元素,而不是collect()
使用findFirst()
/findAny()
。
Optional<Something> s = list.stream()
.filter(ele -> ele.isBlue())
.map(Element::getSomething)
.findAny();
然後你要麼得到一個Optional
含有單一的藍色元素,或空Optional
。
有一個在簡單流findFirst()
和findAny()
之間沒有差異,只有當並行涉及(其中findFirst()
返回確定性的第一元件,和findAny()
將返回它找到任何單個合適的元件)。
你仍然可以collect
,但有一個limit
:
list.stream()
.filter(ele -> ele.isBlue())
.map(Element::getSomething)
.limit(1)
.collect(toList());
值得理解是流管道由最後一步的推動下,終止操作。
不要想到流水線生產商將物品沿傳送帶向下推入等待的消費者,而是想到終止操作拉動物品 - 生產者在詢問時添加了新物品。
在你的例子中,終止操作是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以查看所有終止操作。
'findFirst()。orElse(null)''而不是調用'collect'。如果您使用'parallelStream'並確保流中只有一個元素,則可以使用'findAny()。orElse(null)'代替。 – Lothar
因爲流是懶惰的,所以你只需要'filter(..)。findFirst()。orElse(.. whatever)' –