@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");
        
        FutureImpl<R> future = new FutureImpl<>();

        
        onSuccess(value -> {
            
            
            Try<Future<R>> mapped = Try(() -> function.apply(value));
            
            mapped.recover(t -> Future.failed(t)).forEach(f -> f.onComplete(v -> future.complete(v)));
        });

        
        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)
/ * ( non - Javadoc )