简体   繁体   中英

CompletableFuture<Boolean> as return type does not work as expected

I have a method in Java which should return a CompletableFuture<Boolean<> and I have some issues with the case when it is supposed to be true. My Method is below:

@Override
    public CompletableFuture<Boolean> process(String name, Object data, Object message) {

        switch (name) {
            case ("first"):

                Map<String, Long> finalAmount = (Map<String, Long>) data;
                finalAmount.forEach((id, amount) -> {
                     event.retrieveEvent(id)
                            .thenCompose(config -> {
                                update(id, amount, config);
                                return CompletableFuture.completedFuture(true);
                            });
                });
        }
        return CompletableFuture.completedFuture(false);
    }

The problem is that I have a map and I have to iterate over it and do something for each value. Even though it always enters the part with "CompletableFuture.completedFuture(true)" - in the end, it always goes to the final "return CompletableFuture.completedFuture(false)" and it returns false instead of true.

What can I do and how should I rewrite my method in order to return true after the map elements finish and for each one, everything worked and it returned true?

The code never stops to wait for the result of the case case("first") , so it will schedule a CompletableFuture to compute it and continue to the return CompletableFuture.completedFuture(false); .

This is one possible solution:

@Override
public CompletableFuture<Boolean> process(String name, Object data, Object message) {
        switch (name) {
            case ("first"):
                CompletableFuture<Void> result = CompletableFuture.completedFuture( null );
                Map<String, Long> finalAmount = (Map<String, Long>) data;
                finalAmount.forEach((id, amount) -> {
                     result = result
                         .thenCompose(v -> event.retrieveEvent(id))
                         .thenAccept(config -> update(id, amount, config));
                });
                return result.thenApply(v -> Boolean.TRUE);
             
        }         
        return CompletableFuture.completedFuture(Boolean.FALSE);
    }

If you want to run all the tasks in parallel, an alternative solutions is:

@Override
public CompletableFuture<Boolean> process(String name, Object data, Object message) {
        switch (name) {
            case ("first"):
                Map<String, Long> finalAmount = (Map<String, Long>) data;
                CompletableFuture<Void>[] futures = new CompletableFuture<>[finalAmount.size()];
                AtomicInteger index = new AtomicInteger();
                finalAmount.forEach((id, amount) -> {
                     futures[index.getAndIncrement()] = event
                         .retrieveEvent(id)
                         .thenAccept(config -> update(id, amount, config));
                });
                return CompletableFuture
                    .allOf(futures)
                    .thenApply(v -> Boolean.TRUE);
        }         
        return CompletableFuture.completedFuture(Boolean.FALSE);
    }

Assuming that everything is thread-safe.

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