CompletableFuture are classes provided by Java to represent asynchronous actions.
CompletableFuture are close to
CompletionStage are eager.
When a method returns a
CompletionStage, the operation has already been triggered.
The outcome is used to complete the returned
On the other side,
Unis are lazy.
The operation is only triggered once there is a subscription.
CompletionStage caches the outcome.
So, once received, you can retrieve the result.
Every retrieval will get the same result.
Uni, every subscription has the opportunity to re-trigger the operation and gets a different result.
You can also cache the outcome with
You can create a
CompletionStage<String> cs = uni.subscribeAsCompletionStage();
It’s important to understand that retrieving a
CompletionStage subscribes to the
If you do this operation twice, it subscribes to the
Uni twice and re-trigger the operation.
// Trigger the underlying operation twice: CompletionStage<String> cs1 = uni.subscribeAsCompletionStage(); CompletionStage<String> cs2 = uni.subscribeAsCompletionStage();
To create a
Uni from a
Uni<String> uni1 = Uni // Create from a Completion Stage .createFrom().completionStage( CompletableFuture.supplyAsync(() -> "hello", executor) ) .onItem().transform(String::toUpperCase); Uni<String> uni2 = Uni // Create from a Completion Stage supplier (recommended) .createFrom().completionStage( () -> CompletableFuture.supplyAsync(() -> "hello", executor) ) .onItem().transform(String::toUpperCase);
As you can see, there are two versions.
The first one receives the
CompletionStage directly, while the second one gets a supplier.
In the case of multiple subscriptions on the produced
Uni, the supplier is called multiple times (once per subscription), and so can change the return
It also delays the creation of the
CompletionStage until there is a subscription, which only triggers the operation at that time.
If you pass the instance directly, it will always use the same one (even for multiple subscriptions) and triggers the operation even if there is no subscription.
For these reasons, it is generally better to use the variant accepting a supplier.
Note that if the completion stage produces a
null value, the resulting
null as item.
If the completion stages complete exceptionally, the failure is emitted by the resulting
To create a
Multi from a
a multi emitting an item and completing - if the value produced by the completion stage is not
an empty multi if the value produced by the completion stage is
a failed multi is completion stage is completed exceptionally.
Multi<String> multi1 = Multi .createFrom().completionStage( CompletableFuture.supplyAsync(() -> "hello", executor) ) .onItem().transform(String::toUpperCase); Multi<String> multi2 = Multi .createFrom().completionStage(() -> CompletableFuture.supplyAsync(() -> "hello", executor) ) .onItem().transform(String::toUpperCase);
For the same reason as for
Uni, there are two versions:
one accepting a
one accepting a
Supplier<CompletionStage>, called at subscription-time, for every subscription.
It is recommended to use the second version.