Search code examples
javafunctional-programmingfunctional-interface

Chaining a Function with a BiFunction in Java


I have a Function and BiFunction and I would like to chain them

Function<Integer, String> function = n -> "" + n;
BiFunction<String, Boolean, List<Character>> biFunction =
    (str, isOK) -> Collections.EMPTY_LIST;

Is there a way to chain these two Functions such as the returned value from Function is used as an input to BiFunction?

Pseudocode:

public List<Character> myMethod(int n, boolean isOK) {
    return function.andThen(biFunction).apply([output_of_function], isOK)
}

I couldn't find a way to provide the integer n to Function nor to supply BiFunction with the output of the first Function.

Is it doable?


Solution

  • Default methods andThen() and compose() declared in the interface Function expect another Function as an argument. Hence, it's not possible to fuse Function and BiFunction using these methods (BiFunction and Function doesn't extend each other).

    On the other hand method BiFunction.andThen() expects a Function as argument. But unfortunately it would be applied after BiFunction (i.e. on the result produced by the BiFunction), but you need the opposite, so this option doesn't fit into your use-case.

    As a possible workaround, you can combine a Function and a BiFunction into an aggregate BiFunction expecting the input of the Function function and a boolean value and producing the result generated by the by BiFunction like this:

    public static <T, R, RR> BiFunction<T, Boolean, RR> getCombinedFunction(
        Function<T, R> fun, BiFunction<R, Boolean, RR> biFun
    ) {
        
        return (t, isOk) -> biFun.apply(fun.apply(t), isOk);
    }
    

    It can be used in the following way:

    Function<Integer, String> function = // initializing function
    BiFunction<String, Boolean, List<Character>> biFunction =  // initializing biFunction
        
    List<Character> chars = getCombinedFunction(function, biFunction).apply(12345, true);
    

    Sidenote:

    The preferred way of converting an int into a String is to use static method String.valueOf(). And the function from your example could be expressed as the following method reference:

    Function<Integer, String> function = String::valueOf;