How to link BiFunctions?

I would like to bind BiFunctions, as in the chainWanted method in the code example below.

BiFunction takes a function as an AndThen parameter. Is it possible to somehow connect BiFunctions?

The code here does not compile because of this, and I cannot use BiFunction for a 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); } } 
+6
source share
2 answers

Binding one Function to another works naturally, because the return value of the first function is passed as an argument to the next function, and this return value of the function is passed as an argument to the next function, etc. This does not work naturally with BiFunction because they accept two arguments. The first argument will be the return value from the previous function, but what will be the second argument? This also explains why BiFunction allows BiFunction to bind with andThen to Function instead of another BiFunction .

This suggests that one BiFunction could be associated with another if there was some way to provide a value for the 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 to Function by capturing this local variable from the environment and using it as the second argument.

Here is how it will look.

 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 contains the params argument for subsequent capture. We will call init.andThen() to execute the chain. But this requires Function , while wait is a BiFunction . Instead of using the this::wait method reference, we use a lambda expression

 rwd -> wait.apply(rwd, params) 

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

+3
source

Where should WfParams come from to call wait ? If you want to reuse the same WfParams for all function calls, just put WfParams as a member variable of the class, rather than passing it to each function.

 class Wf { private final WfParams params; public Wf(WfParams params) { this.params = params; } UnaryOperator<RemoteWebDriver> init = this::init; UnaryOperator<RemoteWebDriver> wait = this::wait; Function<RemoteWebDriver,RemoteWebDriver> chain = init.andThen(wait); RemoteWebDriver init(RemoteWebDriver d) { // can use WfParams here return d; } RemoteWebDriver wait(RemoteWebDriver d) { // can use WfParams here return d; } private void start() { chain.apply(null); } public static void main(String[] args) { new Wf(new WfParams()).start(); } } 

Is there any specific reason why you want to use function chains? Why not just call init(...); wait(...); init(...); wait(...); from start() ?

0
source

Source: https://habr.com/ru/post/977554/


All Articles