public static <T, T2, R, C extends Collection<R>, E extends Exception, E2 extends Exception> C flatMap(final T[] a,
            final Try.Function<? super T, ? extends Collection<? extends T2>, E> func,
            final Try.Function<? super T2, ? extends Collection<? extends R>, E2> func2, final IntFunction<? extends C> supplier) throws E, E2 {
        N.checkArgNotNull(func);
        N.checkArgNotNull(func2);

        if (N.isNullOrEmpty(a)) {
            return supplier.apply(0);
        }

        final C result = supplier.apply(a.length);

        for (T e : a) {
            final Collection<? extends T2> c1 = func.apply(e);

            if (N.notNullOrEmpty(c1)) {
                for (T2 e2 : c1) {
                    final Collection<? extends R> c2 = func2.apply(e2);

                    if (N.notNullOrEmpty(c2)) {
                        result.addAll(c2);
                    }
                }
            }
        }

        return result;
    }
public static < T , T2 , R , C extends Collection < R > , E extends Exception , E2 extends Exception > C flatMap ( final T [ ] a , final Try . Function < ? super T , ? extends Collection < ? extends T2 > , E > func , final Try . Function < ? super T2 , ? extends Collection < ? extends R > , E2 > func2 , final IntFunction < ? extends C > supplier ) throws E , E2 { N . checkArgNotNull ( func ) ; N . checkArgNotNull ( func2 ) ; if ( N . isNullOrEmpty ( a ) ) { return supplier . apply ( 0 ) ; } final C result = supplier . apply ( a . length ) ; for ( T e : a ) { final Collection < ? extends T2 > c1 = func . apply ( e ) ; if ( N . notNullOrEmpty ( c1 ) ) { for ( T2 e2 : c1 ) { final Collection < ? extends R > c2 = func2 . apply ( e2 ) ; if ( N . notNullOrEmpty ( c2 ) ) { result . addAll ( c2 ) ; } } } } return result ; }
Mostly it's designed for one-step operation to complete the operation in one step.
<code>java.util.stream.Stream</code> is preferred for multiple phases operation.

@param a
@param func
@param func2
@param supplier
@return
@throws E
@throws E2