我发现我的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方法都存在是有原因的,并且Function或BiFunctions可能并不总是以这种方式是可逆的。您能想到在任何情况下可逆性都不适用的情况吗?

最佳答案

尽管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表达式。

10-06 11:15