要允许对CompletableFuture<Stream<String>>
生成的流进行多次迭代,我正在考虑采用以下方法之一:
将生成的未来转换为CompletableFuture<List<String>>
至:teams.thenApply(st -> st.collect(toList()))
将生成的未来转换为Flux<String>
缓存:Flux.fromStream(teams::join).cache();
Flux<T>
是项目反应堆中Publisher<T>
的实施。
使用案例
我想从数据源获得一个包含英超联赛球队名称的序列(例如Stream<String>
),该数据源提供League
对象Standing[]
(基于足球数据) RESTful API,例如http://api.football-data.org/v1/soccerseasons/445/leagueTable)。使用AsyncHttpClient
和Gson
我们有:
CompletableFuture<Stream<String>> teams = asyncHttpClient
.prepareGet("http://api.football-data.org/v1/soccerseasons/445/leagueTable")
.execute()
.toCompletableFuture()
.thenApply(Response::getResponseBody)
.thenApply(body -> gson.fromJson(body, League.class));
.thenApply(l -> stream(l.standings).map(s -> s.teamName));
要重新使用生成的流,我有两个选择:
1. CompletableFuture<List<String>> res = teams.thenApply(st -> st.collect(toList()))
2. Flux<String> res = Flux.fromStream(teams::join).cache()
Flux<T>
不那么冗长,并提供我所需要的一切。然而,在这种情况下使用它是否正确?
或者我应该使用CompletableFuture<List<String>>
代替?或者还有其他更好的选择吗?
更新了一些想法(2018-03-16):
CompletableFuture<List<String>>
:
List<String>
将继续收集,当我们需要继续处理未来的结果时,可能已经完成。List<T>
中收集这些项目了。 Flux<String>
:
.cache()
并将其转发到下一层,这可以利用反应API,例如卷材反应控制器,例如, @GetMapping(produces =MediaType.TEXT_EVENT_STREAM) public Flux<String> getTeams() {…}
Flux<T>
,我们必须将它包装在可缓存的Flux<T>
(….cache()
)中,这反过来会增加第一次遍历的开销,因为它必须将结果项存储在内部缓存中。答案 0 :(得分:6)
CompletableFuture<Stream<String>> teams = ...;
Flux<String> teamsFlux = Mono.fromFuture(teams).flatMapMany(stream -> Flux.fromStream(stream));
编辑:
Flux.fromStream(teams::join)
是一种代码异味,因为它持有一个线程来从运行在另一个线程上的CompletableFuture中获取结果。
答案 1 :(得分:3)
一旦您下载了联赛表,并且从该表中提取了团队名称,我不确定您是否需要一个反压就绪流来迭代这些项目。将流转换为标准列表(或数组)应该足够好,并且应该具有更好的性能,不是吗?
例如:
String[] teamNames = teams.join().toArray(String[]::new);