web-dev-qa-db-fra.com

Est-il correct de convertir un CompletableFuture <Stream <T>> en Publisher <T>?

Pour autoriser plusieurs itérations sur le flux résultant d'un CompletableFuture<Stream<String>>, J'envisage l'une des approches suivantes:

  1. Convertissez le futur en CompletableFuture<List<String>> Via: teams.thenApply(st -> st.collect(toList()))

  2. 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>>:

  • [PROS] Le 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é.
  • [CONS] Verbosité de la déclaration.
  • [CONS] Si nous ne voulons l'utiliser qu'une seule fois, nous n'avons pas eu besoin de collecter ces éléments dans un List<T>.

Flux<String>:

  • [PROS] Déclaration de concision
  • [PROS] Si nous ne voulons l'utiliser qu'une seule fois, nous pouvons omettre .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() {…}
  • [CONS] Si nous voulons réutiliser ce 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.
21
Miguel Gamboa
    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.

7
youhans

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);
4
Stéphane Appercel