java - permiten - ¿Debería ''Comparable<T>'' ser una ''interfaz funcional''?
java funcional (4)
Bueno, aparte de la discusión de cuán útil es la anotación informativa @FunctionalInterface
(y estoy feliz de que Java 8 no lo requiere para las lambdas).
Comparable
es típicamente una propiedad de un tipo y, por lo tanto, no es un buen candidato para una interfaz funcional. Se describe explícitamente como el orden natural y no toma los dos argumentos de this / that. Por lo tanto, esta propiedad hace que sea improbable que cualquier método operara en un lambda (un argumento similar es aplicable para interfaces de todo lo -able
).
Por lo tanto, los diseñadores de colecciones utilizan una segunda interfaz para esa tarea: Comparator<T>
, y para eso, una implementación lambda es una opción muy natural.
La definición de una interfaz funcional es "Una interfaz funcional es una interfaz que tiene solo un método abstracto (aparte de los métodos de Object) y, por lo tanto, representa un contrato de una sola función".
De acuerdo con esta definición, la Comparable<T>
es definitivamente una interfaz funcional.
La definición de una expresión lambda es "Una expresión lambda es como un método: proporciona una lista de parámetros formales y un cuerpo - una expresión o bloque - expresada en términos de esos parámetros".
La evaluación de una expresión lambda produce una instancia de una interfaz funcional.
Por lo tanto, el propósito de la expresión lambda es poder crear una instancia de la interfaz funcional, implementando la función única de la interfaz funcional. es decir. Permitir la creación de una instancia con la única función.
Veamos Comparable<T>
, ¿esta interfaz está diseñada para usarse como una sola función? es decir. ¿Fue diseñado solo para la creación de instancias con esta única función?
La documentación de Comparable<T>
comienza con "Esta interfaz impone un orden total en los objetos de cada clase que lo implementa. Este ordenamiento se conoce como orden natural de la clase, y el método compareTo de la clase se conoce como su método de comparación natural . "
La oración anterior deja claro que el Comparable<T>
no está diseñado para ser utilizado como una sola función, sino que siempre debe ser implementado por una clase, que tiene un orden natural para sus instancias, agregando esta única función.
¿Qué significaría que no está diseñado para ser creado usando una expresión lambda?
El punto es que no tendríamos ningún objeto que sea solo comparable, está destinado a ser implementado y, por lo tanto, se utiliza como una función adicional para una clase.
Entonces, ¿hay alguna manera en el lenguaje Java, mediante la cual se evita la creación de una expresión lambda para Comparable<T>
? ¿Puede el diseñador de una interfaz decidir que esta interfaz debe implementarse en una clase y no debe crearse como una instancia con este método único mediante el uso de una expresión lambda?
Simplemente porque una interfaz tiene un único método abstracto, no debe considerarse como una interfaz funcional.
Tal vez, si Java proporciona una anotación como NotFunctional, el compilador puede verificar que esta interfaz no se utiliza para la creación de una expresión lambda, por ejemplo.
@NotFunctional
public interface Comparable<T> { public int compareTo(T t); }
El problema proviene de una sutil diferencia entre un "método" y una "función".
El valor de salida de una función depende SOLAMENTE de los argumentos que se ingresan a esa función.
Sin embargo, la salida de un método depende de los argumentos que se ingresan en la función, pero también puede depender del estado del objeto (variables de instancia).
Es decir, cualquier función es un método pero no todos los métodos son funciones.
Por ejemplo, el método de comparación en la interfaz Comparator solo depende de sus argumentos. Sin embargo, el método compareTo en la interfaz Comparable depende del estado del objeto a comparar, por lo que debe implementarse en una clase.
Entonces, incluso Comparable tiene un método de abstención, semánticamente no debe considerarse como una interfaz funcional.
No existe ningún mecanismo para evitar el uso ingenuo de una interfaz que no pretende ser una interfaz funcional. al tener una anotación adicional como @NotFunctional, un diseñador de una interfaz podría declararlo explícitamente, que no debe usarse como lambda. Y de forma predeterminada, si no se especifica ninguna anotación, se puede considerar tan bueno como @Functional, que es actualmente el caso.
Se puede usar una expresión lambda donde se requiere una instancia de una interfaz con un solo método abstracto. Tu escribiste,
Simplemente porque una interfaz tiene un método abstracto único, no debe considerarse como una interfaz funcional.
Esto es exactamente correcto. Tener un solo método abstracto es una propiedad estructural de una interfaz, una que lo hace elegible para ser implementado con un lambda. Sin embargo, si una interfaz tiene sentido o es semánticamente razonable para implementarse con lambda es una historia diferente. Este último es el propósito de la anotación @FunctionalInterface
. Cuando está presente en una interfaz, indica la intención de que la interfaz sea útil para implementarse con un lambda.
En particular, la interfaz Comparable
carece de la anotación @FunctionalInterface
.
Si bien es probable que no tenga sentido usar un lambda como una implementación Comparable
, no parece haber ninguna razón para crear un mecanismo para evitar que esto se haga. No parece que hacer esto sea una fuente de error, lo que sería una buena razón para desarrollar dicho mecanismo. Por el contrario, la anotación @FunctionalInterface
pretende guiar a los programadores en la dirección correcta en lugar de prohibir algo que podría estar mal pero que no parece realmente perjudicial.