Почему @FunctionalInterface не используется на всех интерфейсах в JDK, которые квалифицируются?

Java 8 предоставил нам много интересных способов использования функциональных интерфейсов, а вместе с ними и новую аннотацию: @FunctionalInterface . Его задача – сказать компилятору кричать на нас, если мы не будем придерживаться правил функционального интерфейса (только один абстрактный метод, который требует переопределения).

В этом пакете java.util.function имеется 43 интерфейса с этой аннотацией. Поиск jdk.1.8.0 / src для @FunctionalInterface вызывает только 57 ударов. Почему другие интерфейсы (такие как AutoCloseable), которые могли бы добавить @FunctionalInterface все еще отсутствуют?

В документации аннотаций есть немного неопределенный намек:

«Информативный тип annotations, используемый для указания того, что объявление типа интерфейса предназначено для функционального интерфейса»

Есть ли веская причина НЕ намереваться, что интерфейс, который я разработал (который может просто оказаться функциональным интерфейсом), не может использоваться как один? Оставляет ли это указание на что-либо, кроме того, что он не понимает, что его можно было бы добавить?

Не добавляет ли абстрактные методы к любому опубликованному интерфейсу, который будет винить любого, кто его реализует, функциональный или нет? Я чувствую себя циничным, полагая, что они просто не потрудились охотиться на всех, но какое другое объяснение есть?

Обновление : после просмотра «Должно ли« Comparable »быть« функциональным интерфейсом »? Я нахожу, что у меня все еще есть вопросы. Когда единый интерфейс метода и функциональный интерфейс структурно идентичны, что осталось быть другим? Является ли разница просто именами? Сопоставимые и компараторы достаточно близки к тому же семантически. Оказывается, они разные структурно, хотя так еще не лучший пример …

Есть ли случай, когда SMI структурно хорош для использования в качестве функционального интерфейса, но все же не рекомендуется использовать семантический смысл имени интерфейса и метода? Или, может быть, контракт, подразумеваемый Javadocs?

    Ну, аннотация, документирующая намерение, бесполезна, если вы предполагаете, что всегда есть это намерение.

    Вы назвали пример AutoCloseable который, очевидно, не предназначен для реализации как функция, так как существует Runnable что намного удобнее для функции с ()->void сигнатурой. Предполагается, что class, реализующий AutoCloseable управляет внешним ресурсом, который анонимные classы, реализованные с помощью lambda-выражения, не выполняют.

    Более ясным примером является Comparable , interface не только не предназначен для реализации в виде lambda-выражения, его невозможно реализовать с использованием выражения lambda.


    Возможные причины не маркировать interface с помощью @FunctionalInterface на примере:

    • interface имеет семантику языка программирования, например AutoClosable или Iterable (это вряд ли произойдет для ваших собственных интерфейсов)
    • Не предполагается, что interface имеет произвольные реализации и / или больше идентификатор, чем фактическая реализация, например java.net.ProtocolFamily , или java.lang.reflect.GenericArrayType (обратите внимание, что последний также наследует реализацию по default для getTypeName() бесполезно для lambda-реализаций, полагаясь на toString() )
    • Экземпляры этого interface должны иметь идентификатор, например java.net.ProtocolFamily , java.nio.file.WatchEvent.Modifier и т. Д. Обратите внимание, что они обычно реализуются enum

      Другим примером является java.time.chrono.Era который имеет только один abstract метод, но его спецификация говорит: «Экземпляры Era можно сравнить с помощью оператора == ».

    • interface предназначен для изменения поведения операции, для которой реализация interface без наследования / реализации чего-либо еще не имеет смысла, например, java.rmi.server.Unreferenced
    • Это абстракция общих операций classов, которые должны иметь не только эти операции, например java.io.Closeable , java.io.Flushable , java.lang.Readable
    • Ожидаемое наследование является частью контракта и запрещает реализацию lambda-выражения, например, в java.awt : ActiveEvent должен быть реализован AWTEvent , PrinterGraphics Graphics , то же самое относится к java.awt.print.PrinterGraphics (эй, два interface s для точно такой же вещи …), если javax.print.FlavorException должен быть реализован подclassом javax.print.PrintException
    • Я не знаю, не связаны ли различные интерфейсы прослушивателя событий с @FunctionalInterface для симметрии с другим прослушивателем событий нескольких методов, которые не могут быть функциональными интерфейсами, но на самом деле прослушиватели событий являются хорошими кандидатами для lambda-выражений. Если вы хотите удалить слушателя позднее, вы должны сохранить экземпляр, но это не отличается от, например, реализации внутреннего classа слушателя.
    • У хранителя библиотеки есть большая база кода с более чем 200 типами кандидатов, а не ресурсы для обсуждения для каждого interface , следует ли ее аннотировать и, следовательно, основное внимание уделяется основным кандидатам для использования в функциональном контексте. Я уверен, что, например, java.io.ObjectInputValidation , java.lang.reflect.InvocationHandler , juc RejectedExecutionHandler & ThreadFactory не будет плохой как @FunctionalInterface но я понятия не имею, например, java.security.spec.ECField делает хороший кандидат. Чем более общей является библиотека, тем более вероятным пользователям библиотеки будет возможность ответить на этот вопрос для конкретного interface им интересен, но было бы несправедливо настаивать на том, чтобы разработчик библиотеки отвечал на него для всех интерфейсов.

      В этом контексте имеет смысл видеть присутствие @FunctionalInterface в качестве сообщения о том, что interface определенно должен использоваться вместе с lambda-выражениями, чем рассматривать отсутствие annotations в качестве индикатора, поскольку он не предназначен для использования сюда. Это точно так же, как компилятор справляется с этим, вы можете реализовать каждый отдельный interface абстрактного метода, используя выражение lambda, но когда присутствует аннотация, он будет гарантировать, что вы можете использовать этот interface таким образом.

    Планируемое расширение. Просто потому, что интерфейс соответствует требованиям SMI, это не означает, что расширение не понадобится позже.

    В java 8 функциональный интерфейс является интерфейсом, имеющим ровно один абстрактный метод, называемый функциональным методом, к которому сопоставляются параметр выражения lambda и возвращаемые типы.

    java.util.function содержит функциональные интерфейсы общего назначения, используемые JDK, а также доступные для конечных пользователей . Хотя они не являются полным набором функциональных интерфейсов, к которым могут быть применены lambda-выражения, но они обеспечивают достаточно для удовлетворения общих требований. Вы можете создавать свои собственные функциональные интерфейсы всякий раз, когда существующего набора недостаточно.

    Существует много таких интерфейсов, которые заслуживают того, чтобы их можно было назвать функциональным интерфейсом, но пакет java.util.function уже предоставляет функциональные интерфейсы для наших почти всех целей.

    Например, посмотрите на следующий код.

     public interface Comparable { public int compareTo(T o); } @FunctionalInterface public interface ToIntFunction { int applyAsInt(T value); } public static void main(String[] args){ ToIntFunction f = str -> Integer.parseInt(str); Comparable c = str -> Integer.parseInt(str); } 

    Comparable может также взять объект и получить некоторое значение типа int, но для выполнения этой задачи предусмотрен более общий выделенный интерфейс ToIntFunction . Не существует такого жесткого правила, что все заслуживающие интерфейсы должны быть аннотированы с помощью @FunctionalInterface но для того, чтобы получить преимущество lambda-функции, интерфейс должен выполнять все критерии, определенные FunctionalInterface.

    Interesting Posts
    Давайте будем гением компьютера.