I'm working in a Java 8 application. I have 3 methods that return CompletionStage:
CompletionStage<Edition> editionService.loadById(editionId);
CompletionStage<Event> eventService.loadById(eventId);
CompletionStage<List<EditionDate>> editionDateService.loadByEditionId(editionId);
And a method that consolidates these values into a Result
CompletionStage<Result> getResult(Edition edition, Event event, List<EditionDate> editionDates)
Methods 1 and 3 can be ran independently but calling method 2 depends on the result of method 1. And obviously method 4 depends on all of them to run. My question is, what's the best way to call these methods using CompletableFuture api; this is the best I can come up with but I'm not sure it's the best way to do it:
editionService.loadById(editionId)
.thenCompose(edition -> eventService.loadById(edition.getEventId()))
.thenCombine(editionDateService.loadByEditionId(editionId),
(event, editionDates) -> getResult(edition, event, editionDates) );
But this way I don't have access to my edition
result so I'm in a little bit of a loss. Any method I should be using that I'm not taking into account?
You can write it as
CompletionStage<Result> result = editionService.loadById(editionId)
.thenCompose(edition -> eventService.loadById(edition.getEventId())
.thenCombine(editionDateService.loadByEditionId(editionId),
(event, editionDates) -> getResult(edition, event, editionDates) ) )
.thenCompose(Function.identity());
but then, editionDateService.loadByEditionId
will be triggered only after editionService.loadById
has been completed, which is an unnecessary dependency.
The simplest solution is not to try to write everything as a single expression:
CompletionStage<List<EditionDate>> datesStage=editionDateService.loadByEditionId(editionId);
CompletionStage<Result> result = editionService.loadById(editionId)
.thenCompose(edition -> eventService.loadById(edition.getEventId())
.thenCombine(datesStage, (event, dates) -> getResult(edition, event, dates)))
.thenCompose(Function.identity());
easiest solution would be to have the edition available from inside the event. Or to have the call to 2 wrapped in anoher method that return a pair(edition, event) instead
Something like the following code looks good to me but not able to test it with only that piece of your code, so up to you to test it and make it cleaner. This is only a proof of concept :)
public static class Pair{
public Edition edition;
public Event event;
public Pair(Edition edition, Event event) {
this.edition = edition;
this.event = event;
}
}
public static CompletionStage<Pair> wrap(Edition edition){
CompletionStage<Event> event = eventService.loadById(edition.getEventId());
return event.thenApply(ev -> new Pair(edition, ev));
}
public static void main(String[] args) {
int editionId = 42;
editionService.loadById(editionId)
.thenCompose(edition -> wrap(edition))
.thenCombine(editionDateService.loadByEditionId(editionId),
(wrapped, editionDates) -> getResult(wrapped.edition, wrapped.event, editionDates) );
}
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.