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

41 Views Asked by At

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?

1

There are 1 best solutions below

3
DuncG On BEST ANSWER

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