Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to chain BiFunctions?

I would like to chain BiFunctions, like in the method chainWanted in the code sample below.

BiFunction takes Function as a parameter of AndThen. is it possible to somehow chain BiFunctions ?

The code here doesn't compile because of this and I cannot cast BiFunction to Function.

import java.util.function.BiFunction;
import java.util.function.Function;

import org.openqa.selenium.remote.RemoteWebDriver;

public class Wf {

    BiFunction<RemoteWebDriver, WfParams, RemoteWebDriver> init = this::init;
    BiFunction<RemoteWebDriver, WfParams, RemoteWebDriver> wait = this::wait;

    BiFunction<RemoteWebDriver, WfParams, RemoteWebDriver> chainNow = init
            .andThen(d -> {
                System.out.println("--------------");
                return null;
            });

    BiFunction<RemoteWebDriver, WfParams, RemoteWebDriver> chainWanted = init
            .andThen((BiFunction) wait);

    public RemoteWebDriver init(RemoteWebDriver d, WfParams params) {
        System.out.println("init(d, params)");
        return d;
    }

    public RemoteWebDriver wait(RemoteWebDriver d, WfParams params) {
        System.out.println("Wf.wait(d, params)");
        return d;
    }

    public static void main(String[] args) throws Exception {
        new Wf().start();
    }

    private void start() {
        chainNow.apply(null, null);
    }
}
like image 820
Pan Bydlak Avatar asked Oct 31 '14 16:10

Pan Bydlak


People also ask

How does Java BiFunction work?

Represents a function that accepts two arguments and produces a result. This is the two-arity specialization of Function . This is a functional interface whose functional method is apply(Object, Object) .

What is function chaining in Java 8?

Function in Java 8A Function is a functional interface (has a single abstract method called accept) that accepts one argument and produces a result. Example: We can create a stream of integers, map each integer element to double (2x) of its value, and collect the result as a list.

What are the methods of BiFunction interface?

The BiFunction interface consists of the following two functions: This method applies the given function to the arguments. Parameters: This method takes two parameters: Returns: This method returns the function result which is of type R. Below is the code to illustrate apply () method:

What is BiFunction in Java with example?

Java BiFunction methods and Examples R apply (T t, U u) – Applies this function to the given arguments and produces results. default BiFunction andThen ( Function after) – Returns a composed function that first applies this function to its input, and then applies the after function to the result. 1.1. BiFunction basic Example

How do I chain a course email with two functions?

The key to chaining: Pass in courseEmail as an argument to both functions, and on line 12 let courseEmail await getEmailOfCourseWithCourseId (). Result: The two following functions that we’ve passed courseEmail as an argument to will both wait until courseEmail is ready (aka the function has been run and promise has resolved), then run.

Is it possible to Cascade multiple function objects to form a BiFunction?

However, it is possible to cascade two or more Function objects to form a BiFunction but in that case it won’t be possible to use both the parameters at the same time. This is the utility of BiFunction.


1 Answers

Chaining of one Function to another works naturally because the return value of the first function is passed as the argument to the next function, and that function's return value is passed as the argument to the subsequent function, and so forth. This doesn't work naturally with BiFunction because they take two arguments. The first argument would be the return value from the previous function, but what would the second argument be? It also explains why BiFunction allows chaining with andThen to a Function instead of to another BiFunction.

This suggests, however, that it would be possible to chain one BiFunction to another if there were some way of providing the value for second argument. This can be done by creating a helper function that stores the value for the second argument in a local variable. Then, a BiFunction can be converted into a Function by capturing that local variable from the environment and using it as the second argument.

Here's what that would look like.

BiFunction<RemoteWebDriver, WfParams, RemoteWebDriver> chainWanted = this::chainHelper;

RemoteWebDriver chainHelper(RemoteWebDriver driver, WfParams params) {
    return
        init.andThen(rwd -> wait.apply(rwd, params))
            .apply(driver, params);
}

// ...

chainWanted.apply(driver, params);

The chainHelper method holds the params argument for later capture. We call init.andThen() in order to do the chaining. But this requires a Function whereas wait is a BiFunction. Instead of using a method reference this::wait we use the lambda expression

rwd -> wait.apply(rwd, params)

which captures params from the lexical environment. This gives a lambda expression that takes a single argument and returns a single value, so it's now a Function that wraps the wait which is a BiFunction. This is an example of partial application or currying. Finally, we call the resulting BiFunction using apply(), passing the original arguments.

like image 100
Stuart Marks Avatar answered Oct 23 '22 00:10

Stuart Marks