Search code examples
javalambdaexecutorservice

How to deal with lambda expression on a Executor/FutureTask flow?


Here's my task class:

public interface TaskCallback {
    void onTaskCompleted(Boolean result);
    void onTaskFailed(Exception e);
}

public class AsyncTaskExample {
    private final Executor executor = Executors.newSingleThreadExecutor();

    public void executeAsyncTask(TaskCallback callback) {
        FutureTask<Boolean> taskSyncFiles = new FutureTask<>(() -> {
            // task
            return true;
        });

        executor.execute(taskSyncFiles);
        executor.execute(() -> {
            try {
                Boolean result = taskSyncFiles.get();
                callback.onTaskCompleted(result);
            } catch (InterruptedException | ExecutionException e) {
                callback.onTaskFailed(e);
            }
        });
    }
}

I'd like from another method (Activity in Android) call async the task and catch the callback as lambda, somethings like:

myTask.executeAsyncTask(result -> {
    System.out.println("Task completed with result: " + result);
}, e -> {
    e.printStackTrace();
});

but can't get it working. How can I do it correctly?


Solution

  • The use of 2 separate lambdas does not give you an instance of TaskCallback. You have 2 easy workarounds. Firstly you could eliminate need for TaskCallback and pass in two Consumers and process each one:

    public void executeAsyncTask(Consumer<Boolean> onTaskCompleted, Consumer<Exception> onTaskFailed) {
        ...
        executor.execute(() -> {
            try {
                Boolean result = taskSyncFiles.get();
                onTaskCompleted.accept(result);
            } catch (InterruptedException | ExecutionException e) {
                onTaskFailed.accept(e);
            }
        });
    

    Alternatively define a wrapper class for TaskCallback and construct one with lambdas:

    myTask.executeAsyncTask(new MyTaskCallback(result -> {
        System.out.println("Task completed with result: " + result);
    }, e -> {
        e.printStackTrace();
    }));
    

    You can use directly as above or overload the call to create one internally:

    public void executeAsyncTask(Consumer<Boolean> onTaskCompleted, Consumer<Exception> onTaskFailed) {
        executeAsyncTask(new MyTaskCallback(onTaskCompleted, onTaskFailed));
    }
    

    Here is a simple record declaration that supports the call, you can adjust as a similar class declaration suitable for use with whatever works in Android Java:

    record MyTaskCallback(Consumer<Boolean> onTaskCompleted, Consumer<Exception> onTaskFailed) implements TaskCallback {
        public void onTaskCompleted(Boolean result) {
            onTaskCompleted.accept(result);
        }
    
        public void onTaskFailed(Exception e) {
            onTaskFailed.accept(e);
        }
    }