I have this code:
CompletableFuture<ApplicationUserDto> byUserName = applicationUserService
.findByUserName(getCurrentApplicationUserName());
CompletableFuture<List<FocusDto>> focuses = focusService.findMine(byUserName.join().getFacilities());
CompletableFuture.allOf(byUserName, focuses).join();
Iterable<IdmDataFacade> facilities = idmService.lookupFacilities(new HashSet<>(byUserName.join().getFacilities())).toIterable();
So in focusService.findMine
i'm dependent on the result from
applicationUserService.findByUserName(getCurrentApplicationUserName())
But in my frontend tests all data is displayed in the right way and manner.
I´ve read about thenCompose
method on CompletableFuture
so i tested this code:
CompletableFuture<ApplicationUserDto> byUserName = applicationUserService
.findByUserName(getCurrentApplicationUserName());
CompletableFuture<List<FocusDto>> focuses = byUserName
.thenComposeAsync((result) -> focusService.findMine(result.getFacilities()));
CompletableFuture.allOf(byUserName, focuses).join();
Iterable<IdmDataFacade> facilities = idmService.lookupFacilities(new HashSet<>(byUserName.join().getFacilities())).toIterable();
Both code snippets lead to the exact same results. In the log i can see the threads being used. Even these are equal.
So my questions:
Is
CompletableFuture
so smart to know that it has to wait forbyUserName
completion to fill in the parameter infocusService.findMine(byUserName.join().getFacilities())
Which piece of code is better to be used?
CodePudding user response:
- Is CompletableFuture so smart to know that it has to wait for byUserName completion to fill in the parameter in focusService.findMine(byUserName.join().getFacilities())
That's the purpose of the .join
: wait until the result is ready and return it. If you write code like this:
CompletableFuture<ApplicationUserDto> byUserName = applicationUserService
.findByUserName(getCurrentApplicationUserName());
CompletableFuture<List<FocusDto>> focuses = focusService.findMine(byUserName.join().getFacilities());
You are telling the application to block the execution and wait for byUserName
to complete before calling findMine
, so that you have the parameter for .findMine
.
This also means that you don't need to call .allOf
after, because you already know that .byUserName
is completed.
You could rewrite everything like this:
Iterable<IdmDataFacade> facilities = applicationUserService
.findByUserName(getCurrentApplicationUserName())
.thenCompose(byUserNameResult -> focusService
.findMine(byUserNameResult.getFacilities())
.thenApply(findMineResult -> idmService
.lookupFacilities(new HashSet<>(byUserNameResult.getFacilities())).toIterable()
)
)
.join();
- Which piece of code is better to be used?
Who knows? It depends what you are trying to achieve. Usually, it doesn't make sense to .join
after every CompletionStage
if you are using them.