I currently convert my CompletableFuture<X>
to CompletableFuture<Void>
as shown below but I was wondering if there was a better way.
@Override
public CompletableFuture<Void> packetEncrypted(ByteBuffer engineToSocketData) {
return realChannel.write(engineToSocketData).thenApply(c -> empty());
}
public Void empty() {
return null;
}
As such, there's nothing you can do through CompletableFuture to interrupt any thread that may be running some task that will complete it. You'll have to write your own logic which tracks any Thread instances which acquire a reference to the CompletableFuture with the intention to complete it.
Calling toCompletableFuture() on the returned instance will yield a CompletableFuture , but invocation of the completion methods ( complete() and other methods in the complete*() and obtrude*() families) on that CompletableFuture instance will result in UnsupportedOperationException being thrown.
CompletableFuture executes these tasks in a thread obtained from the global ForkJoinPool. commonPool(). But we can also create a Thread Pool and pass it to runAsync() and supplyAsync() methods to let them execute their tasks in a thread obtained from our thread pool.
Future vs CompletableFuture. CompletableFuture is an extension to Java's Future API which was introduced in Java 5. A Future is used as a reference to the result of an asynchronous computation.
You're effectively trying to transform the completed value of your CompletableFuture
into a value of type Void
. Presumably you want to propagate any exception if that future was completed exceptionally.
CompletableFuture
provides thenApply
for this basic transformation, but other methods can also be used.
In your case, you'll want to ignore the value from the source future and return null
, since null
is the only possible value for the type Void
. However, there needs to be some hint for the compiler that you're targeting the type Void
.
Either be explicit by providing an explicit type argument to the invocation of thenApply
public CompletableFuture<Void> packetEncrypted(ByteBuffer engineToSocketData) {
return realChannel.write(engineToSocketData).<Void> thenApply(c -> null);
}
or be explicit by casting to the appropriate type in the lambda expression
public CompletableFuture<Void> packetEncrypted(ByteBuffer engineToSocketData) {
return realChannel.write(engineToSocketData).thenApply(c -> (Void) null);
}
Your solution achieves the same result, since the value is known to be of the correct type, but it involves an extra method invocation
@Override
public CompletableFuture<Void> packetEncrypted(ByteBuffer engineToSocketData) {
return realChannel.write(engineToSocketData).thenApply(c -> empty());
}
All of these solutions will propagate the exception, if any, of the origial CompletableFuture
.
Thank you to Luis, you could also just use thenAccept
with a Consumer
doing nothing:
public CompletableFuture<Void> packetEncrypted(ByteBuffer engineToSocketData) {
return realChannel.write(engineToSocketData).thenAccept(c -> {}):
}
The behavior is the same for any other type. thenApply
lets you perform any Function
on the result of a CompletableFuture
.
For example, I can have a future that's meant to complete with String
that's meant to be converted to an Integer
.
public static void main(String[] args) throws Exception {
CompletableFuture<String> futureLine = CompletableFuture.supplyAsync(() -> "1234");
CompletableFuture<Integer> theNumber = futureLine.thenApply(Integer::parseInt);
System.out.println(theNumber.get());
}
thenApply
receives the completed value and transforms it by passing it to an invocation of Integer#parseInt(String)
. Since parseInt
has a return type of int
, the return type of thenApply
is inferred to CompletableFuture<Integer>
.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With