ItFreak
ItFreak

Reputation: 2369

Java CompletableFuture chain calls on interface

I have some workflow abstraction that relies on an interface WorkflowStep:

public interface WorkflowStep {

    public void executeStep();
}

Now I have got three different classes that implement this interface:

GetCoordinatesForWaypoints, DisplayDetails, PlaySounds

My aim is to chain them with CompletableFuture, currently each overriden executeStep() method runs in a runnable, like shown here for example:

public class GetCoordinatesForEndpoints implements WorkflowStep {
    @Override
    public void executeStep() {
        new Thread(new Runnable() {
            @Override
            public void run() {
              //download coordinates from open street map
        }).start();

    }
}

The other classes methods look similiar. Now I have a central class where the workflow is started. Currently it looks like this:

public class DetailsDispatchWorkflow implements DispatchWorkflow {
    private List<WorkflowStep> workflowSteps;

    public DetailsDispatchWorkflow() {
        workflowSteps = new LinkedList<>();
    }

    @Override
    public void start() {
        workflowSteps.add(new GetCoordinatesForEndpoints());
        workflowSteps.add(new DisplayDetails());
        workflowSteps.add(new PlaySounds());
        workflowSteps.forEach(WorkflowStep::executeStep);
    }
}

Now I want to replace this with CompletableFutures. The first thing I tried was to do something like this:

ExecutorService executorService = Executors.newFixedThreadPool(5);
CompletableFuture<WorkflowStep> workflowStepCompletableFuture = 
CompletableFuture.supplyAsync(() -> new 
GetCoordinatesForEndpoints().executeStep(), executorService);

which gives me an error (I think because the called method returns void). Calling only the constructor works. My next step is to chain those calls with thenAccept (because the called actions do not return a value), but that does not work either, when I append

.thenAccept(() -> new DisplayDetails().executeStep(), executorService);

I get an error that the compiler cannot infer the functional interface type. My quesiton is: How can I achieve the following call chain:

CompletableFuture<WorkflowStep> workflowStepCompletableFuture = 
    CompletableFuture
        .supplyAsync(() -> new GetCoordinatesForEndpoints().executeStep(), executorService)
        .thenAccept(() -> new DisplayDetails().executeStep(), executorService)
        .thenAcceptAsync(() -> new PlaySounds().executeStep(), executorService);

when all instantiated objects implement the same interface?

Upvotes: 1

Views: 383

Answers (1)

Didier L
Didier L

Reputation: 20608

Your WorkflowStep interface is basically equivalent to Runnable: no input, no output. In the CompletableFuture API, you should thus use the corresponding runAsync() and thenRunAsync() methods:

CompletableFuture<Void> workflowStepCompletableFuture = 
    CompletableFuture
        .runAsync(() -> new GetCoordinatesForEndpoints().executeStep(), executorService)
        .thenRunAsync(() -> new DisplayDetails().executeStep(), executorService)
        .thenRunAsync(() -> new PlaySounds().executeStep(), executorService);

This will make all of them run asynchronously, but in sequence (as it seems you are trying to do).

Of course you should also remove the Thread creation from your implementation to make this useful.

Upvotes: 1

Related Questions