¿Las expresiones lambda tienen algún otro uso que no sea guardar líneas de código?
¿Existen características especiales proporcionadas por lambdas que resolvieron problemas que no eran fáciles de resolver? El uso típico que he visto es que en lugar de escribir esto:
Comparator<Developer> byName = new Comparator<Developer>() {
@Override
public int compare(Developer o1, Developer o2) {
return o1.getName().compareTo(o2.getName());
}
};
Podemos usar una expresión lambda para acortar el código:
Comparator<Developer> byName =
(Developer o1, Developer o2) -> o1.getName().compareTo(o2.getName());
(o1, o2) -> o1.getName().compareTo(o2.getName())
Comparator.comparing(Developer::getName)
Respuestas:
Las expresiones lambda no cambian el conjunto de problemas que puede resolver con Java en general, pero definitivamente facilitan la resolución de ciertos problemas, por la misma razón que ya no estamos programando en lenguaje ensamblador. Eliminar las tareas redundantes del trabajo del programador facilita la vida y permite hacer cosas que ni siquiera tocarías de otra manera, solo por la cantidad de código que tendrías que producir (manualmente).
Pero las expresiones lambda no solo guardan líneas de código. Las expresiones lambda le permiten definir funciones , algo para lo que antes podía usar clases internas anónimas como solución alternativa, por eso puede reemplazar las clases internas anónimas en estos casos, pero no en general.
En particular, las expresiones lambda se definen independientemente de la interfaz funcional a la que se convertirán, por lo que no hay miembros heredados a los que puedan acceder, además, no pueden acceder a la instancia del tipo que implementa la interfaz funcional. Dentro de una expresión lambda,
this
ysuper
tienen el mismo significado que en el contexto circundante, consulte también esta respuesta . Además, no puede crear nuevas variables locales que sombreen las variables locales del contexto circundante. Para la tarea prevista de definir una función, esto elimina muchas fuentes de error, pero también implica que para otros casos de uso, puede haber clases internas anónimas que no se pueden convertir en una expresión lambda, incluso si se implementa una interfaz funcional.Además, la construcción
new Type() { … }
garantiza producir una nueva instancia distinta (comonew
siempre lo hace). Las instancias de clases internas anónimas siempre mantienen una referencia a su instancia externa si se crean en unstatic
contexto no . Por el contrario, las expresiones lambda solo capturan una referenciathis
cuando es necesario, es decir, si accedenthis
o un nostatic
miembro. Y producen instancias de una identidad no especificada intencionalmente, lo que permite que la implementación decida en tiempo de ejecución si reutiliza las instancias existentes (consulte también “ ¿Una expresión lambda crea un objeto en el montón cada vez que se ejecuta? ”).Estas diferencias se aplican a su ejemplo. Su construcción de clase interna anónima siempre producirá una nueva instancia, también puede capturar una referencia a la instancia externa, mientras que su
(Developer o1, Developer o2) -> o1.getName().compareTo(o2.getName())
es una expresión lambda que no captura y que evaluará a un singleton en implementaciones típicas. Además, no.class
genera un archivo en su disco duro.Dadas las diferencias en cuanto a semántica y rendimiento, las expresiones lambda pueden cambiar la forma en que los programadores resolverán ciertos problemas en el futuro, por supuesto, también debido a que las nuevas API adoptan ideas de programación funcional utilizando las nuevas características del lenguaje. Consulte también Expresión lambda de Java 8 y valores de primera clase .
fuente
Los lenguajes de programación no son para que las máquinas los ejecuten.
Son para que los programadores piensen en ellos.
Los lenguajes son una conversación con un compilador para convertir nuestros pensamientos en algo que una máquina pueda ejecutar. Una de las principales quejas sobre Java de las personas que acuden a ella desde otras lenguas (o dejan que para otros idiomas) que solía ser que obliga a un determinado modelo mental en el programador (es decir, todo lo que es una clase).
No voy a opinar si eso es bueno o malo: todo son compensaciones. Pero las lambdas de Java 8 permiten a los programadores pensar en términos de funciones , que es algo que antes no podía hacer en Java.
Es lo mismo que un programador procedimental que aprende a pensar en términos de clases cuando llega a Java: los ves pasar gradualmente de clases que son estructuras glorificadas y tienen clases 'auxiliares' con un montón de métodos estáticos y pasan a algo que se parece más a un diseño OO racional (mea culpa).
Si solo piensa en ellos como una forma más corta de expresar clases internas anónimas, entonces probablemente no los encontrará muy impresionantes de la misma manera que el programador de procedimientos anterior probablemente no pensó que las clases fueran una gran mejora.
fuente
Guardar líneas de código puede verse como una nueva característica, si le permite escribir una parte sustancial de la lógica de una manera más corta y clara, lo que a otros les lleva menos tiempo leer y comprender.
Sin expresiones lambda (y / o referencias a métodos), las
Stream
canalizaciones habrían sido mucho menos legibles.Piense, por ejemplo, en cómo se
Stream
vería la siguiente canalización si reemplazara cada expresión lambda con una instancia de clase anónima.Podría ser:
Esto es mucho más difícil de escribir que la versión con expresiones lambda y es mucho más propensa a errores. También es más difícil de entender.
Y esta es una tubería relativamente corta.
Para que esto sea legible sin expresiones lambda y referencias a métodos, habría tenido que definir variables que contengan las diversas instancias de interfaz funcional que se utilizan aquí, lo que habría dividido la lógica de la canalización, lo que lo haría más difícil de entender.
fuente
Comparator
for,sorted
ya que se compara en orden natural de todos modos. ¿Quizás cambiarlo para comparar la longitud de las cadenas o similar, para hacer el ejemplo aún mejor?compareToIgnoreCase
para que se comporte diferente asorted()
.compareToIgnoreCase
sigue siendo un mal ejemplo, ya que simplemente podría utilizar elString.CASE_INSENSITIVE_ORDER
comparador existente . La sugerencia de @tobias_k de comparar por longitud (o cualquier otra propiedad que no tenga un comparador incorporado) encaja mejor. A juzgar por los ejemplos de código de SO Q&A, las lambdas causaron muchas implementaciones innecesarias de comparadores…Iteración interna
Al iterar las colecciones de Java, la mayoría de los desarrolladores tienden a obtener un elemento y luego procesarlo . Es decir, saque ese elemento y luego úselo, o vuelva a insertarlo, etc. Con las versiones anteriores a 8 de Java, puede implementar una clase interna y hacer algo como:
Ahora con Java 8 puede hacerlo mejor y menos detallado con:
o mejor
Comportamientos como argumentos
Adivina el siguiente caso:
Con la interfaz de Java 8 Predicate puedes hacerlo mejor así:
Llamándolo como:
Fuente: DZone - Por qué necesitamos expresiones Lambda en Java
fuente
numbers.forEach((Integer value) -> System.out.println(value));
la expresión lambda está formada por dos partes, la de la izquierda del símbolo de flecha (->) que enumera sus parámetros y la de la derecha que contiene su cuerpo . El compilador se da cuenta automáticamente de que la expresión lambda tiene la misma firma del único método no implementado de la interfaz del consumidor.Hay muchos beneficios de usar lambdas en lugar de la clase interna que se muestra a continuación:
Haga que el código sea más compacto y expresivo sin introducir más semántica de sintaxis del lenguaje. ya dio un ejemplo en su pregunta.
Al usar lambdas, está feliz de programar con operaciones de estilo funcional en flujos de elementos, como transformaciones de reducción de mapas en colecciones. consulte la documentación de los paquetes java.util.function y java.util.stream .
El compilador no genera ningún archivo de clases físicas para lambdas. Por lo tanto, reduce las aplicaciones entregadas. ¿Cómo se asigna Memory a lambda?
El compilador optimizará la creación de lambda si el lambda no accede a las variables fuera de su alcance, lo que significa que la instancia de lambda solo se crea una vez por la JVM. para obtener más detalles, puede ver la respuesta de @ Holger a la pregunta ¿Es una buena idea el almacenamiento en caché de referencias de métodos en Java 8? .
Lambdas puede implementar interfaces de marcadores múltiples además de la interfaz funcional, pero las clases internas anónimas no pueden implementar más interfaces, por ejemplo:
fuente
Las lambdas son simplemente azúcar sintáctico para clases anónimas.
Antes de las lambdas, se pueden usar clases anónimas para lograr lo mismo. Cada expresión lambda se puede convertir en una clase anónima.
Si está utilizando IntelliJ IDEA, puede hacer la conversión por usted:
fuente
Para responder a su pregunta, el hecho es que las lambdas no le permiten hacer nada que no pudiera hacer antes de java-8, sino que le permite escribir un código más conciso . Los beneficios de esto es que su código será más claro y flexible.
fuente
Una cosa que no veo mencionada todavía es que una lambda le permite definir la funcionalidad donde se usa .
Entonces, si tiene una función de selección simple, no necesita colocarla en un lugar separado con un montón de texto repetitivo, simplemente escriba una lambda que sea concisa y localmente relevante.
fuente
Sí, hay muchas ventajas.
fuente