Pour autoriser plusieurs itérations sur le flux résultant d'un CompletableFuture<Stream<String>>
, J'envisage l'une des approches suivantes:
Convertissez le futur en CompletableFuture<List<String>>
Via: teams.thenApply(st -> st.collect(toList()))
Convertissez le futur en Flux<String>
Avec le cache: Flux.fromStream(teams::join).cache();
Flux<T>
Est l'implémentation de Publisher<T>
Dans le réacteur du projet.
Cas d'utilisation:
Je voudrais obtenir une séquence avec les noms des équipes de Premier League (par exemple Stream<String>
) À partir d'une source de données qui fournit un objet League
avec un Standing[]
(Basé sur des données de football API RESTful, par exemple http://api.football-data.org/v1/soccerseasons/445/leagueTable ). En utilisant AsyncHttpClient
et Gson
, nous avons:
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));
Pour réutiliser le flux résultant, j'ai deux options:
1. CompletableFuture<List<String>> res = teams.thenApply(st -> st.collect(toList()))
2. Flux<String> res = Flux.fromStream(teams::join).cache()
Flux<T>
Est moins verbeux et fournit tout ce dont j'ai besoin. Pourtant, est-il correct de l'utiliser dans ce scénario?
Ou dois-je utiliser CompletableFuture<List<String>>
À la place? Ou existe-t-il une autre meilleure alternative?
MISE À JOUR avec quelques réflexions (2018-03-16) :
CompletableFuture<List<String>>
:
List<String>
Sera collecté dans une continuation et quand nous devons procéder avec le résultat du futur, il est peut-être déjà terminé.List<T>
.Flux<String>
:
.cache()
et le transmettre à la couche suivante, qui peut tirer parti de l'API réactive, par exemple contrôleur réactif de flux Web, par ex. @GetMapping(produces =MediaType.TEXT_EVENT_STREAM) public Flux<String> getTeams() {…}
Flux<T>
, Nous devons l'envelopper dans un Flux<T>
(….cache()
) qui, à son tour, ajoutera des frais généraux lors de la première traversée, car il doit stocker les éléments résultants dans un cache interne. CompletableFuture<Stream<String>> teams = ...;
Flux<String> teamsFlux = Mono.fromFuture(teams).flatMapMany(stream -> Flux.fromStream(stream));
Flux.fromStream(teams::join)
est une odeur de code car il contient un thread pour récupérer le résultat de CompletableFuture qui s'exécute sur un autre thread.
Une fois que vous avez téléchargé le tableau de ligue et que les noms des équipes sont extraits de ce tableau, je ne suis pas sûr que vous ayez besoin d'un flux prêt à contre-pression pour parcourir ces éléments. Une conversion du flux vers une liste (ou un tableau) standard devrait être suffisante et devrait probablement avoir de meilleures performances, non?
Par exemple:
String[] teamNames = teams.join().toArray(String[]::new);