Java 8 Functions - compose and andthen

2022-09-02 14:22:38

我发现我的Java知识与Java 8过时了,并且我正在尝试学习许多新的语言功能。其中之一是函数,特别是 和 方法。composeandThen

我写了一个微不足道的实验来测试 和 的可逆性:composeandThen

/** Wraps a value 
 */
public class Wrap<T> {
    private final T value;
    private Wrap(T value) {
        this.value = value;
    }
    public static <T> Wrap<T> of(T value) {
        return new Wrap<>(value);
    }
}

static void functions() {

    Function<Integer,String> itos = i->"'"+i+"'";
    Function<String,Wrap<String>> stow = s->Wrap.of(s);

    Function<Integer,Wrap<String>> itow = itos.andThen(stow);
    Function<Integer,Wrap<String>> itow2 = stow.compose(itos);

    System.out.println(itow.apply(3));
    System.out.println(itow2.apply(3));
}

在上面的代码中,正如预期的那样,这两个函数似乎等效。但它们实际上是等价的吗?在这种情况下,是否有相同的结果有些偶然?itowitow2

人们认为,和方法的存在是有原因的,并且函数或双函数可能并不总是以这种方式可逆的。你能想到任何可逆性不适用的情况吗?composeandThen


答案 1

虽然等价于 ,但在使用端存在实际差异,当这两个函数中只有一个是已经存在的函数时。a.andThen(b)b.compose(a)

假设您有已经存在的函数

Function<Integer, String> iToHex = i -> "'" + Integer.toHexString(i) + "'";

然后,您想要链接字符串转换,例如

Function<Integer, String> itoUpperHex = iToHex.andThen(String::toUpperCase);

andThen显然比起

Function<Integer,String> itoUpperHex
                       = ((Function<String,String>)String::toUpperCase).compose(iToHex);

另一方面,如果您已经存在的函数是

Function<String, String> quote = s -> "'" + s + "'";

并且您想要创建带引号的十六进制函数,

Function<Integer, String> iToHex = quote.compose(Integer::toHexString);

会更方便,相比

Function<Integer, String> iToHex = ((Function<Integer, String>) Integer::toHexString).andThen(quote);

因此,任何一种方法的决定都取决于哪个函数已经存在。如果两者都已存在,则使用哪种方法并不重要(除非您怀疑这些函数之一可能已覆盖这些方法以执行更有效的组合)。如果您没有现有函数作为起点,则没有理由使用这些方法中的任何一个,因为您可以将组合表达式编写为单个 lambda 表达式。


答案 2

它们是等效的。

或者换句话说:与 相同。x.andThen(y)y.compose(x)