src/main/java/javascalautils/concurrent/FutureImpl.java
@Override
    public <R> Future<R> flatMap(ThrowableFunction1<T, Future<R>> function) {
        Validator.requireNonNull(function, "Null is not a valid function");
        // Create new future expected to hold the value of the mapped type
        FutureImpl<R> future = new FutureImpl<>();

        // install success handler that will map the result before applying it
        onSuccess(value -> {
            // use the provided function to create a mapped future
            //it might actually fail due to the provided function throws an exception, hence we wrap it with a Try
            Try<Future<R>> mapped = Try(() -> function.apply(value));
            //add a recover function to the Try that fails this future with the error, else we complete this Future with the mapped Future
            mapped.recover(t -> Future.failed(t)).forEach(f -> f.onComplete(v -> future.complete(v)));
        });

        // install failure handler that just passes the failure/result through
        onFailure(t -> future.failure(t));

        return future;
    }
@Override
    public <R> Future<R> flatMap(ThrowableFunction1<T, Future<R>> function) {
        Validator.requireNonNull(function, "Null is not a valid function");
        // Create new future expected to hold the value of the mapped type
        FutureImpl<R> future = new FutureImpl<>();

        // install success handler that will map the result before applying it
        onSuccess(value -> {
            // use the provided function to create a mapped future
            //it might actually fail due to the provided function throws an exception, hence we wrap it with a Try
            Try<Future<R>> mapped = Try(() -> function.apply(value));
            //add a recover function to the Try that fails this future with the error, else we complete this Future with the mapped Future
            mapped.recover(t -> Future.failed(t)).forEach(f -> f.onComplete(v -> future.complete(v)));
        });

        // install failure handler that just passes the failure/result through
        onFailure(t -> future.failure(t));

        return future;
    }
/*
(non-Javadoc)

@see javascalautils.concurrent.Future#flatMap(java.util.function.Function)