【问题标题】:Functional Interface Inheritance Quirk函数式接口继承怪癖
【发布时间】:2015-08-18 12:22:57
【问题描述】:

我有一个使用了一段时间的自定义界面,看起来像这样:

public interface Function<T, R> {
    R call(T input);
}

我想用 Java 的 Function 和 Guava 的 Function 来改造这个接口,同时保持它的 FunctionalInterface。我以为我有完美的安排:

@FunctionalInterface
public interface Function<T, R> extends
        java.util.function.Function<T, R>,
        com.google.common.base.Function<T, R> {

    R call(T input);

    @Override
    default R apply(T input) {
        return call(input);
    }
}

两个超接口都声明了相同的apply()方法,在我的接口中已经实现了,只剩下抽象的call()方法。奇怪的是,它不会编译,告诉我

'@FunctionalInterface' 注释无效; Function 不是函数式接口

更奇怪的是,以下变体编译得很好:

@FunctionalInterface
public interface Function<T, R> extends
        java.util.function.Function<T, R> {

    R call(T input);

    @Override
    default R apply(T input) {
        return call(input);
    }
}

@FunctionalInterface
public interface Function<T, R> extends
        com.google.common.base.Function<T, R> {

    R call(T input);

    @Override
    default R apply(T input) {
        return call(input);
    }
}

public interface Function<T, R> extends
        java.util.function.Function<T, R>,
        com.google.common.base.Function<T, R> {

    R call(T input);

    @Override
    default R apply(T input) {
        return call(input);
    }
}

@FunctionalInterface
public interface Function<T, R> extends
        java.util.function.Function<T, R>,
        com.google.common.base.Function<T, R> {

    @Override
    R apply(T input);
}

第一个版本无法编译是否有原因?

【问题讨论】:

  • 第三个编译成功,因为您没有添加它必须是 @FunctionalInterface 的约束(这是编译器验证的注释)。
  • @SotiriosDelimanolis,很明显。
  • 你在用 Eclipse 编译吗?用 Oracle 的编译器编译得很好。
  • 这应该编译并且确实使用 javac 编译。看起来像一个 Eclipse 错误.... 另外我不确定您为什么要这样做 - 功能接口的主要目的是创建 lambda,方法的名称无关紧要。所以这个 lambda a -&gt; doSomething(a) 可以分配给 3 个 Functions 接口中的任何一个...
  • @assylias,假设我有一个接受我的Function 的方法,我想重构它以接受任何Java Function。或者说我有一个 Function 的实例,我希望能够将它传递给 Guava 方法。

标签: java lambda java-8 default-method functional-interface


【解决方案1】:

如 cmets 中所述,使用 oracle 编译器可以正常编译。 这是一个 Eclipse 错误。

等待错误修复,我个人将删除注释@FunctionalInterface(您的第三个变体):

public interface Function<T, R>
                                extends
                                    java.util.function.Function<T, R>,
                                    com.google.common.base.Function<T, R> {

    R call(T input);

    @Override
    default R apply(T input) {
        return call(input);
    }
}

此解决方案的主要不便之处在于 eclipse 编译器错误阻止将 Function 用作 lambda target type


如果你真的想在你的Function 上保留@FunctionalInterface,一个(丑陋的)解决方法可能是引入一个中间接口:

public interface AdapterFunction<T, R>
                                      extends
                                          java.util.function.Function<T, R>,
                                          com.google.common.base.Function<T, R> {
    @Override
    default R apply(T input) {
        return null;
    }
}

让你的Function 扩展这个AdapterFunction

@FunctionalInterface
public interface Function<T, R>
                                extends
                                    AdapterFunction<T, R> {

    R call(T input);

    @Override
    default R apply(T input) {
        return call(input);
    }
}

在这种情况下,Function 也是 eclipse 的有效目标类型:

Function<String, Object> function = st -> st.toString();

【讨论】:

  • 是的,我发现了一个类似的错误报告here。我不关心注释本身;问题是它不允许我使用 lambda 表达式。我尝试了与您的适配器想法类似的方法,但没有成功。我明天再试一次。
  • AdapterFunction 的解决方案也适用于 Eclipse。但删除 @FunctionalInterface(第 3 变体)不会
  • 你是对的,它可以在适配器中实现apply()。谢谢!
  • "此解决方案的主要不便之处在于您不能将 Function 用作 lambda 目标类型" => 为什么不呢?您不需要将接口标记为@FunctionalInterface 也不需要用作 lambda 的目标类型,只要它实际上是一个功能接口...
  • @assylias 你理论上是对的,但实际上eclipse编译器不接受它。它仅适用于 oracle 编译器
猜你喜欢
  • 1970-01-01
  • 2021-04-10
  • 1970-01-01
  • 2011-06-21
  • 2016-02-17
  • 1970-01-01
  • 2010-09-21
相关资源
最近更新 更多