如何链接BiFunctions?

时间:2014-10-31 16:49:23

标签: java functional-programming java-8

我想链接BiFunctions,就像下面代码示例中的方法chainWanted一样。

BiFunction将Function作为AndThen的参数。有可能以某种方式链接BiFunctions吗?

这里的代码没有因为这个而编译,我无法将BiFunction转换为函数。

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);
    }
}

3 个答案:

答案 0 :(得分:6)

将一个Function链接到另一个自然起作用,因为第一个函数的返回值作为参数传递给下一个函数,并且该函数的返回值作为参数传递给后续函数,因此向前。这与BiFunction无关,因为它们有两个参数。第一个参数是前一个函数的返回值,但第二个参数是什么?它还解释了为什么BiFunction允许andThenFunction而不是BiFunction进行链接。

然而,这表明如果有某种方式为第二个参数提供值,则可以将一个BiFunction链接到另一个BiFunction。这可以通过创建一个辅助函数来完成,该函数将第二个参数的值存储在局部变量中。然后,通过从环境中捕获该局部变量并将其用作第二个参数,可以将Function转换为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);

这就是看起来的样子。

chainHelper

params方法保存init.andThen()参数以便以后捕获。我们调用Function来进行链接。但这需要wait,而BiFunctionthis::wait。我们使用lambda表达式

而不是使用方法引用rwd -> wait.apply(rwd, params)
params

从词汇环境中捕获Function。这给出了一个lambda表达式,它接受一个参数并返回一个值,所以它现在是一个wait,它包裹BiFunction BiFunction。这是部分应用 currying 的示例。最后,我们使用apply()调用生成的{{1}},并传递原始参数。

答案 1 :(得分:0)

WfParams应该从哪里来调用wait?如果您要为所有函数调用重用相同的WfParams,只需将WfParams作为类成员变量,而不是将其传递给每个函数。

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();
    }   
}

您是否有特殊原因要使用功能链?为什么不从init(...); wait(...);致电start()

答案 2 :(得分:0)

我做了这样的事情-创建了我的自定义BiFunction。 这个想法是:

  1. 返回类型与第二个参数相同

  2. 第一个参数在内部传递给链接的biFunction

    public interface BiFunctionCustom<T, U> extends BiFunction<T,U,U> {
    
      default BiFunctionCustom<T, U> andThen(BiFunctionCustom<T, U> after) {
          Objects.requireNonNull(after);
          return (T t, U u) -> after.apply(t, apply(t, u));
      }
    }