功能接口继承怪癖

Functional Interface Inheritance Quirk

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

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

我想用 Java 的 Function as well as Guava's Function, while keeping it a 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()方法。奇怪的是,它不会编译,告诉我

Invalid '@FunctionalInterface' annotation; Function<T,R> is not a functional interface

还是陌生人,以下变体编译得很好:

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

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

如评论中所述,使用 oracle 编译器可以很好地编译它。 这是一个日食错误。

等待错误修复,我个人将删除注释 @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();