[英]Java 8 : Stream : Consuming steps to save Intermediate States of streamed elements
首先,對這個抽象標題感到抱歉。 舉個例子,這個想法更簡單。 假設我在列表L中有一些值。我想構建請求服務的參數,然后調用該服務並收集所有響應。
目前,我正在使用這種代碼結構:
private final List<String> bodies = ImmutableList.of(
"1", "2", "3", "4"
);
@Test
public void BasicRequestResponseStreamToList() {
final List<Request> requests = bodies.stream()
.map(Request::new)
.collect(Collectors.toList());
final List<Response> responses = requests.stream()
.map(service::send)
.collect(Collectors.toList());
commonAssertions(requests, responses);
}
但是,考慮到必須在發送第一個請求之前構建最后一個請求,我發現兩個流的效率不高。 我想做類似的事情:
@Test
public void StatefulMapperStreamRequestResponseToList() {
final List<Request> requests = new ArrayList<>();
final List<Response> responses = bodies.stream()
.map(Request::new)
.map(x -> {
requests.add(x);
return service.send(x);
})
.collect(Collectors.toList());
commonAssertions(requests, responses);
}
但是,我對將這樣的“ Hack”用於映射語義感到內。 但是,這是我發現用延遲加載構建2個相關列表的唯一方法。 第一個解決方案對我不感興趣,因為它必須等待構建所有請求,然后再發送它們。 我很想在EIP中實現類似竊聽的功能。 http://camel.apache.org/wire-tap.html
與修改map方法的語義來實現這一目標相比,我很樂意讓您想到一種更優雅的方式。
如果有幫助,您可以在這里找到源: http : //tinyurl.com/hojkdzu
使用.peek()
雖然需要在代碼中進行較少的更改,但實際上是一個很骯臟的解決方案。 您需要它,因為您的原始代碼中存在設計缺陷。 您具有“並行數據結構”(可能是術語不是很好): requests
列表中的第一個元素對應於responses
列表中的第一個元素,依此類推。 遇到這種情況時,請考慮創建一個新的PoJo類。 像這樣:
public class RequestAndResponse { // You may think up a better name
public final Request req; // use getters if you don't like public final fields
public final Response resp;
public RequestAndResponse(Request req, Response resp) {
this.req = req;
this.resp = resp;
}
}
現在,您的問題神奇地消失了。 你可以寫:
List<RequestAndResponse> reqresp = bodies.stream()
.map(Request::new)
.map(req -> new RequestAndResponse(req, service.send(req)))
.collect(Collectors.toList());
commonAssertions(reqresp);
之后,您將需要更改commonAssertions
方法,但是我敢肯定它會變得更簡單。 您還可能會發現代碼中的某些方法將請求和響應一起使用,因此將它們作為RequestAndResponse
類中的方法是很自然的。
不知道您真正想要在這里實現什么。 但是,如果您想要“隨您走”收集請求,則可以使用peek()
:
final List<Request> requests = new ArrayList<>();
final List<Response> responses = bodies.stream()
.map(Request::new)
.peek(requests::add)
.map(service::send)
.collect(Collectors.toList());
commonAssertions(requests, responses);
.peek()
與您在帖子主題中的意思.peek()
; 它需要一個Consumer
,它可以在管道中的任何步驟發生,並且此處消費者只是將“中間狀態”保存到列表中。
但是... peek()
的javadoc特別提到了這一點:
對於並行流管道,可以在任何時間和線程中通過上游操作使元素可用,以調用該操作。 如果操作修改了共享狀態,則它負責提供所需的同步。
所以,好吧,我想...
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.