Dado que Java8 se lanzó recientemente y sus nuevas expresiones lambda parecen ser realmente geniales, me preguntaba si esto significaría la desaparición de las clases Anónimas a las que estábamos tan acostumbrados.
He estado investigando un poco sobre esto y encontré algunos ejemplos interesantes sobre cómo las expresiones Lambda reemplazarán sistemáticamente esas clases, como el método de ordenación de Collection, que solía obtener una instancia anónima de Comparator para realizar la ordenación:
Collections.sort(personList, new Comparator<Person>(){
public int compare(Person p1, Person p2){
return p1.firstName.compareTo(p2.firstName);
}
});
Ahora se puede hacer usando Lambdas:
Collections.sort(personList, (Person p1, Person p2) -> p1.firstName.compareTo(p2.firstName));
Y parece sorprendentemente conciso. Entonces, mi pregunta es, ¿hay alguna razón para seguir usando esas clases en Java8 en lugar de Lambdas?
EDITAR
La misma pregunta pero en la dirección opuesta, ¿cuáles son los beneficios de usar Lambdas en lugar de clases anónimas, ya que Lambdas solo se puede usar con interfaces de un solo método, esta nueva característica es solo un acceso directo solo se usa en pocos casos o es realmente útil?
fuente
Comparator.comparing(Person::getFirstName)
sigetFirstName()
sería un método que regresafirstName
.Respuestas:
Se puede usar una clase interna anónima (AIC) para crear una subclase de una clase abstracta o una clase concreta. Un AIC también puede proporcionar una implementación concreta de una interfaz, incluida la adición de estado (campos). Se puede hacer referencia a una instancia de un AIC
this
en los cuerpos de sus métodos, por lo que se pueden llamar a otros métodos, su estado se puede mutar con el tiempo, etc. Ninguno de estos se aplica a las lambdas.Supongo que la mayoría de los usos de los AIC eran para proporcionar implementaciones sin estado de funciones únicas y, por lo tanto, pueden reemplazarse con expresiones lambda, pero hay otros usos de AIC para los que no se pueden usar lambdas. Los AIC llegaron para quedarse.
ACTUALIZAR
Otra diferencia entre las AIC y las expresiones lambda es que las AIC introducen un nuevo alcance. Es decir, los nombres se resuelven a partir de las superclases e interfaces de AIC y pueden ocultar nombres que se producen en el entorno que los encierra léxicamente. Para lambdas, todos los nombres se resuelven léxicamente.
fuente
A$1.class
pero Lambda no lo hará. ¿Puedo agregar esto en Diferencia?LambdaClass$$Lambda$1/1078694789
. Sin embargo, esta clase es generada sobre la marcha por la metafábrica lambda, no porjavac
, por lo que no hay un.class
archivo correspondiente . Una vez más, sin embargo, esta es una preocupación de implementación.Lambdas, aunque es una gran característica, solo funcionará con tipos SAM. Es decir, interfaces con un único método abstracto. Fallará tan pronto como su interfaz contenga más de 1 método abstracto. Ahí es donde las clases anónimas serán útiles.
Entonces, no, no podemos simplemente ignorar las clases anónimas. Y solo para su información, su
sort()
método puede simplificarse más, omitiendo la declaración de tipo parap1
yp2
:También puede utilizar la referencia de método aquí. O agrega un
compareByFirstName()
método en laPerson
clase y usa:o, agregue un getter para
firstName
, obtenga directamente el métodoComparator
fromComparator.comparing()
:fuente
new @MyTypeAnnotation SomeInterface(){};
. Esto no es posible para las expresiones lambda. Para obtener más detalles, consulte mi pregunta aquí: Anotar la interfaz funcional de una expresión Lambda .Rendimiento Lambda con clases anónimas
Cuando se lanza la aplicación, se debe cargar y verificar cada archivo de clase.
Las clases anónimas son procesadas por el compilador como un nuevo subtipo para la clase o interfaz dada, por lo que se generará un nuevo archivo de clase para cada una.
Las lambdas son diferentes en la generación de códigos de bytes, son más eficientes, utilizan la instrucción dinámica invocada que viene con JDK7.
Para Lambdas, esta instrucción se utiliza para retrasar la traducción de la expresión lambda en código de bytes hasta el tiempo de ejecución. (la instrucción se invocará solo por primera vez)
Como resultado, la expresión Lambda se convertirá en un método estático (creado en tiempo de ejecución). (Hay una pequeña diferencia con los casos stateles y statefull, se resuelven mediante argumentos de método generados)
fuente
invokedynamic
cuales generalmente son más lentas que lasinvokespecial
utilizadas para crear nuevas instancias de clases anónimas. Entonces, en este sentido, las lambdas también son más lentas (sin embargo, JVM puede optimizar lasinvokedynamic
llamadas la mayor parte del tiempo).invokedynamic
generación de clases ad-hoc es increíblemente rápida en comparación con las clases anónimas compiladas.Existen las siguientes diferencias:
1) Sintaxis
Las expresiones lambda se ven ordenadas en comparación con la clase interna anónima (AIC)
2. Alcance
Una clase interna anónima es una clase, lo que significa que tiene un ámbito para la variable definida dentro de la clase interna.
Mientras, expresión lambda no es un ámbito en sí mismo, sino que es parte del ámbito adjunto.
Se aplica una regla similar para super y esta palabra clave cuando se usa dentro de una clase interna anónima y una expresión lambda. En el caso de una clase interna anónima, esta palabra clave se refiere al ámbito local y la palabra clave super se refiere a la superclase de la clase anónima. Mientras que en el caso de la expresión lambda, esta palabra clave se refiere al objeto del tipo envolvente y super se referirá a la superclase de la clase envolvente.
3) Rendimiento
En tiempo de ejecución, las clases internas anónimas requieren carga de clases, asignación de memoria e inicialización de objetos e invocación de un método no estático, mientras que la expresión lambda es pura actividad en tiempo de compilación y no genera costos adicionales durante el tiempo de ejecución. Entonces, el rendimiento de la expresión lambda es mejor en comparación con las clases internas anónimas. **
** Me doy cuenta de que este punto no es del todo cierto. Consulte la siguiente pregunta para obtener más detalles. Lambda vs rendimiento de clase interna anónima: ¿reducir la carga en ClassLoader?
fuente
Lambda en Java 8 se introdujo para la programación funcional. Donde puede evitar el código repetitivo. Encontré este interesante artículo sobre lambda.
http://radar.oreilly.com/2014/04/whats-new-in-java-8-lambdas.html
Es recomendable utilizar funciones lambda para lógicas simples. Si implementar lógica compleja usando lambdas será una sobrecarga en la depuración del código en caso de problema.
fuente
La clase anónima está ahí para quedarse porque lambda es buena para funciones con métodos abstractos únicos, pero para todos los demás casos, las clases internas anónimas son su salvador.
fuente
invoke dynamic
, lambda no se vuelve a convertir a las clases anónimas durante el tiempo de compilación (Java no tiene que pasar por la creación de objetos, solo se preocupa por la firma del método, puede unirse al método sin crear un objetofuente