¿Por qué no se usa @FunctionalInterface en todas las interfaces en el JDK que califican?

Java 8 nos dio muchas formas divertidas de usar interfaces funcionales y con ellas una nueva anotación: @FunctionalInterface . Su trabajo es decirle al comstackdor que nos grite si no nos apegamos a las reglas de una interfaz funcional (solo un método abstracto que debe prevalecer, por favor).

Hay 43 interfaces en el paquete java.util.function con esta anotación. Una búsqueda de jdk.1.8.0 / src para @FunctionalInterface solo aparece 57 hits. ¿Por qué las demás interfaces (como AutoCloseable) que podrían haber agregado @FunctionalInterface todavía lo @FunctionalInterface menos?

Hay un poco de una sugerencia vaga en la documentación de las anotaciones :

“Un tipo de anotación informativa utilizado para indicar que una statement de tipo de interfaz debe ser una interfaz funcional”

¿Hay alguna buena razón para NO intentar que una interfaz que he diseñado (que simplemente puede ser una interfaz funcional) no se utilice como tal? ¿Dejarlo como indicación de algo además de no darme cuenta de que podría haber sido agregado?

¿No está agregando métodos abstractos a cualquier interfaz publicada para atornillar a cualquiera que lo implemente, funcional o no? Me siento cínico asumiendo que simplemente no se molestaron en cazarlos a todos, pero ¿qué otra explicación hay?

Actualización : después de revisar “¿Debería ser” Comparable “una” Interfaz funcional “? Me parece que todavía tengo preguntas persistentes. Cuando una interfaz de método único y una interfaz funcional son estructuralmente idénticas, lo que queda por ser diferente? ¿La diferencia es simplemente los nombres? Comparable y Comparador están lo suficientemente cerca de la misma semánticamente. Resulta que son diferentes estructuralmente, por lo que todavía no es el mejor ejemplo …

¿Hay algún caso en el que una SMI sea estructuralmente adecuada para usar como interfaz funcional, pero aún desaconseja el significado semántico del nombre de la interfaz y el método? ¿O tal vez el contrato implicado por los Javadocs?

Bueno, una anotación que documente una intención sería inútil si supone que siempre hay esa intención.

AutoCloseable el ejemplo AutoCloseable que obviamente no está destinado a ser implementado como una función ya que Runnable es mucho más conveniente para una función con una firma ()->void . Se pretende que una clase que implementa AutoCloseable administre un recurso externo que las clases anónimas implementadas a través de la expresión lambda no hacen.

Un ejemplo más claro es Comparable , una interface no solo no implementada como una expresión lambda, sino que es imposible implementarla correctamente utilizando una expresión lambda.


Posibles razones para no marcar una interface con @FunctionalInterface por ejemplo:

  • La interface tiene semántica del lenguaje de progtwigción, por ejemplo, AutoClosable o Iterable (que es poco probable que suceda para sus propias interfaces)
  • No se espera que la interface tenga implementaciones arbitrarias y / o sea más un identificador que la implementación real, por ejemplo, java.net.ProtocolFamily o java.lang.reflect.GenericArrayType (Tenga en cuenta que este último también heredaría una implementación default para getTypeName() ser inútil para implementaciones lambda como confiar en toString() )
  • Las instancias de esta interface deben tener una identidad, por ejemplo, java.net.ProtocolFamily , java.nio.file.WatchEvent.Modifier , etc. Tenga en cuenta que estas suelen ser implementadas por una enum

    Otro ejemplo es java.time.chrono.Era que tiene solo un único método abstract pero su especificación dice “Las instancias de Era se pueden comparar usando el operador == “.

  • La interface está destinada a alterar el comportamiento de una operación para la cual una implementación de la interface sin heredar / implementar cualquier otra cosa no tiene sentido, por ejemplo java.rmi.server.Unreferenced
  • Es una abstracción de las operaciones comunes de clases que deberían tener más que solo estas operaciones, por ejemplo, java.io.Flushable , java.io.Flushable , java.lang.Readable
  • La herencia esperada es parte del contrato y prohíbe las implementaciones de expresión lambda, por ejemplo, en java.awt : un AWTEvent , PrinterGraphics mediante un Graphics , implementará AWTEvent , lo mismo se aplica a java.awt.print.PrinterGraphics (hey, two interface s exactamente lo mismo …), donde javax.print.FlavorException debe ser implementado por una subclase javax.print.PrintException
  • No sé si las diversas interfaces de escucha de eventos no están marcadas con @FunctionalInterface para la simetría con otro oyente de eventos de múltiples métodos que no pueden ser interfaces funcionales, sino que en realidad los oyentes de eventos son buenos candidatos para las expresiones lambda. Si desea eliminar un oyente en otro momento, debe almacenar la instancia, pero eso no es diferente, por ejemplo, las implementaciones de escucha de clase interna.
  • El mantenedor de la biblioteca tiene una gran base de código con más de 200 tipos de candidatos y no los recursos para analizar en cada interface si debe ser anotada y, por lo tanto, se centra en los candidatos principales para ser utilizados en un contexto funcional. Estoy seguro de que, por ejemplo, java.io.ObjectInputValidation , java.lang.reflect.InvocationHandler , juc RejectedExecutionHandler & ThreadFactory no estaría mal como @FunctionalInterface pero no tengo idea si, por ejemplo, java.security.spec.ECField hace un buen candidato Cuanto más general sea la biblioteca, más probable será que los usuarios de la biblioteca puedan responder esa pregunta para una interface particular que les interese, pero sería injusto insistir en que el mantenedor de la biblioteca responda para todas las interfaces.

    En este contexto, tiene más sentido ver la presencia de @FunctionalInterface como un mensaje de que una interface está destinada definitivamente a ser utilizada junto con expresiones lambda que tratar la ausencia de la anotación como un indicador de que no está destinado a ser utilizado. de esta manera. Esto es exactamente como lo maneja el comstackdor, puede implementar cada interface método abstracto usando una expresión lambda, pero cuando la anotación está presente, se asegurará de que pueda usar esta interface de esta manera.

Expansión planificada El hecho de que una interfaz coincida con los requisitos de una SMI ahora no significa que la expansión no sea necesaria más adelante.

En java 8, la interfaz funcional es una interfaz que tiene exactamente un método abstracto llamado método funcional al que se corresponden los parámetros y los tipos de retorno de la expresión lambda.

La función java.util.function contiene interfaces funcionales de uso general utilizadas por JDK y también están disponibles para los usuarios finales . Si bien no son el conjunto completo de interfaces funcionales a las que las expresiones lambda podrían ser aplicables, sí proporcionan lo suficiente para cubrir los requisitos comunes. Usted es libre de crear sus propias interfaces funcionales cuando el conjunto existente no sea suficiente.

Hay muchas interfaces disponibles que merecen designarse como interfaz funcional, pero el paquete java.util.function ya proporciona interfaces funcionales para casi todos los propósitos.

Por ejemplo, busque en el siguiente código.

 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 también puede tomar un objeto y derivar algún tipo de valor int pero hay una interfaz dedicada más general ToIntFunction se proporciona para realizar esta tarea. No existe una norma tan @FunctionalInterface que todas las interfaces que lo merecen se deben anotar con @FunctionalInterface pero para obtener la ventaja de la función lambda, la interfaz debe cumplir todos los criterios definidos por FunctionalInterface.

Intereting Posts