Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How do you transform a CompletableFuture of one type to another?

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;
}
like image 953
Dean Hiller Avatar asked May 11 '16 02:05

Dean Hiller


People also ask

How do I interrupt CompletableFuture?

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.

What does CompletableFuture return?

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.

Is CompletableFuture a thread?

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.

What is the difference between Future and CompletableFuture?

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.


1 Answers

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

like image 193
Sotirios Delimanolis Avatar answered Oct 20 '22 07:10

Sotirios Delimanolis