java lambda java-8

¿Se compilan las lambdas de Java 8 como clases internas, métodos u otra cosa?



java-8 (4)

La expresión en sí, suponiendo que pase una expresión lambda real y no una referencia de método, se compila como un método sintético separado. Además de cualquier argumento formal a la interfaz funcional esperada (por ejemplo, una sola String en el caso de Consumer<String> ), incluirá argumentos para cualquier valor capturado.

En la ubicación del código donde aparece una expresión lambda o referencia de método, se emite una instrucción invokedynamic . La primera vez que se golpea esta instrucción, se realiza una llamada en un método de arranque en LambdaMetafactory . Este método de arranque arreglará una implementación real de la interfaz funcional de destino que delega al método de destino, y esto es lo que se devuelve. El método de destino es el método sintético que representa el cuerpo lambda o el método nombrado que se proporcionó utilizando el operador :: . Mientras se crea una clase que implementa la interfaz funcional, el proceso se difiere; No sucede en tiempo de compilación.

Finalmente, el tiempo de ejecución invokedynamic sitio invokedynamic con el resultado de bootstrap 1 , que es efectivamente una llamada de constructor al delegado generado con cualquier valor capturado pasado, incluido (posiblemente) un objetivo de invocación 2 . Esto alivia el impacto en el rendimiento al eliminar el proceso de arranque para las llamadas posteriores.

1 Ver java.lang.invoke al final del capítulo "sincronización del enlace" , cortesía de @Holger.

2 En el caso de una lambda que no captura, la instrucción invokedynamic generalmente se resolverá en una instancia de delegado compartida que se puede reutilizar durante las llamadas posteriores, aunque este es un detalle de implementación.

Hoy he leído este artículo sobre lambdas:

http://www.infoq.com/articles/Java-8-Lambdas-A-Peek-Under-the-Hood

El artículo sugiere que las lambdas no se implementan como clases internas anon (debido al rendimiento). Da un ejemplo de que una expresión lambda puede compilarse como un método de clase (estático).

He probado un fragmento muy simple:

private void run() { System.out.println(this); giveHello(System.out::println); } private void giveHello(Consumer<String> consumer) { System.out.println(consumer); consumer.accept("hello"); }

y la salida es:

sample.Main@14ae5a5 sample.Main$$Lambda$1/168423058@4a574795 hello

Entonces no es la misma instancia. Tampoco es una instancia central de "Fábrica Lambda".

¿Cómo se implementan las lambdas entonces?


Las Lambda en Java 8 se denominan interfaces funcionales, es decir, interfaces anónimas con un método default .


Me hice la misma pregunta y encontré este video , una charla de Brian Goetz. Es una introducción muy útil a cómo se implementan las lambdas en Java.

Editar (resumen): lo vi hace un tiempo, por lo que esto podría no ser completamente correcto. Cuando se compilan los archivos, el compilador deja una descripción de lo que debe hacer el lambda. El JRE, luego cuando ejecuta el código, decidirá cómo implementar el lambda. Hay varias opciones, en línea, referencia de método, clase anónima. Luego utilizará la asignación dinámica para asignar la implementación.


No estoy seguro, pero creo que solo se está compilando en la clase interna Anónimo. Consumer<T> es una interfaz, por lo que diría que su ejemplo es casi igual a

giveHello(new Consumer<String>() { @Override public void accept(String t) { System.out.println(t); } });

EDITAR

Después de algunas investigaciones, la respuesta anterior no es completa y válida. Las expresiones lambda pueden traducirse a una clase interna anónima, pero no tienen que hacerlo (y generalmente no lo hacen).