【问题标题】:Java 8 extending function interface and combining themJava 8 扩展函数接口并将它们组合起来
【发布时间】:2016-05-03 23:02:31
【问题描述】:

我有一个函数式接口,可以将标准 jdk 函数扩展到简单的泛型类型。现在我想使用 andThen 组合两个函数,这会引发编译器错误

Error:(25, 25) java: method andThen in interface java.util.function.Function<T,R> 不能应用于给定类型;
必需:java.util.function.Function<? super ui.instrumentation.api.messaging.Message<R>,? extends V> 找到: ui.instrumentation.api.transformation.Transformer&lt;T,R&gt;原因: 无法推断类型变量 V (参数不匹配;ui.instrumentation.api.transformation.Transformer&lt;T,R&gt; 不能 转换为java.util.function.Function<? super ui.instrumentation.api.messaging.Message<R>,? extends V>)

这里是示例代码:

public interface Transformer<T,R> extends Function<Message<T>, Message<R>> {

    static <T, R> Transformer<T, R> combine2(Transformer<T, R> first, Transformer<T, R> second) {
        return first.andThen(second));
    } 
}

有没有一种方法可以组合扩展标准 Function 接口的函数,或者有更好的方法吗?

【问题讨论】:

  • 为什么你需要combine2 函数,而andThen 做同样的事情,对于更一般的参数类型Function
  • 所以你想要一个函数,它接受一个Message&lt;T&gt;,将它传递给first,得到一个Message&lt;R&gt;,然后以某种方式将Message&lt;R&gt;传递给second,即使second需要Message&lt;T&gt; 而不是Message&lt;R&gt;
  • 我的建议:不要使用这样的扩展接口。以不允许使用基本接口的现有实现为代价(此处为Function),您可以节省一些要输入的字母。因此,您需要重新实现所有内容,不仅andThen,甚至像Function.identity()这样的琐碎函数也不能用作Transformer。从别人的错误中吸取教训;尽管具有相同的功能签名,但您不能使用Transformer&lt;T,T&gt;,其中需要UnaryOperator&lt;Message&lt;T&gt;&gt;(另一个不允许基类型Function 的示例)...

标签: java lambda functional-programming java-8


【解决方案1】:

你需要修复你的泛型,而不是使用andThen,它只会返回一个Function,你最好自己内联lambda:

static <T1, T2, T3> Transformer<T1, T3> combine2(Transformer<T1, T2> first, Transformer<T2, T3> second) {
    return (Message<T1> input) -> second.apply(first.apply(input));
} 

【讨论】:

    【解决方案2】:

    第一个问题是andThen 获取一个函数的返回值并将其作为下一个函数的参数类型,因此您需要,正如@LouisWasserman 解释的那样,将它们与输出类型端到端链接一个匹配下一个的输入类型:

    static <T1, T2, T3> Transformer<T1, T3> combine2(Transformer<T1, T2> first, Transformer<T2, T3> second) {
    

    第二个问题,正如他所解释的那样,您正在调用的Function.andThen 返回一个Function,而不是Transformer。但是请注意,FunctionTransformer 具有相同的形状——单输入,单输出。因此,您可以使用一个,然后通过如下方法引用将其调整为另一个:

    static <T1, T2, T3> Transformer<T1, T3> combine(Transformer<T1, T2> first, Transformer<T2, T3> second) {
        return first.andThen(second)::apply;
    }
    

    您无需创建函数即可执行此操作。您可以使用相同的技术直接调用Function.andThen()

        Transformer<String,Integer> t1 = ...
        Transformer<Integer,Double> t2 = ...
        Transformer<Double,String> t3 = ...
    
        Transformer<String,String> t123 = t1.andThen(t2).andThen(t3)::apply;
    

    【讨论】:

    • 感谢@HankD 和@LouisWasserman,帮助我更好地理解。我最初的目标是通过将它们与 andThen 链接来组合许多函数的列表(例如变压器)。看起来我真的需要像这样static &lt;T1, T2, T3, T4&gt; Transformer&lt;T1, T4&gt; combine(Transformer&lt;T1, T2&gt; first, Transformer&lt;T2, T3&gt; second, Transformer&lt;T3, T4&gt; third) { return first.andThen(second).andThen(third)::apply; } 为每个额外的转换器覆盖组合方法@ 有没有更好的方法来更通用地组合函数列表?
    • 我已经更新了我的答案,以展示您如何做到这一点
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-07-06
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多