Подтвердить что ты не робот

Наследование функционального интерфейса Quirk

У меня есть пользовательский интерфейс, который я использовал в течение некоторого времени, который выглядит примерно так:

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; Функция < T, R > не является функциональным интерфейсом

Незнакомец, следующие вариации скомпилируются просто:

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

Есть ли причина, по которой первая версия не будет компилироваться?

4b9b3361

Ответ 1

Как указано в комментариях, он компилируется с помощью компилятора 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 в качестве лямбда-целевого типа.


Если вы действительно хотите сохранить @FunctionalInterface на своем Function, обходным путем (уродливым) может быть представление промежуточного интерфейса:

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();