简体   繁体   中英

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;
}

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

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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM