Cuando itero sobre una colección usando el nuevo azúcar sintáctico de Java 8, como
myStream.forEach(item -> {
// do something useful
});
¿No es esto equivalente al fragmento de 'sintaxis anterior' a continuación?
myStream.forEach(new Consumer<Item>() {
@Override
public void accept(Item item) {
// do something useful
}
});
¿Significa esto Consumer
que se crea un nuevo objeto anónimo en el montón cada vez que itero sobre una colección? ¿Cuánto espacio de almacenamiento ocupa esto? ¿Qué implicaciones de rendimiento tiene? ¿Significa que debería usar el estilo antiguo para los bucles al iterar sobre grandes estructuras de datos de varios niveles?
Respuestas:
Es equivalente pero no idéntico. Simplemente dicho, si una expresión lambda no captura valores, será un singleton que se reutilizará en cada invocación.
El comportamiento no se especifica exactamente. La JVM tiene una gran libertad sobre cómo implementarla. Actualmente, la JVM de Oracle crea (al menos) una instancia por expresión lambda (es decir, no comparte instancia entre diferentes expresiones idénticas) pero crea tonos únicos para todas las expresiones que no capturan valores.
Puede leer esta respuesta para más detalles. Allí, no solo di una descripción más detallada sino que también probé el código para observar el comportamiento actual.
Esto está cubierto por la especificación del lenguaje Java®, capítulo “ 15.27.4. Evaluación en tiempo de ejecución de expresiones lambda ”
Resumido:
fuente
Cuando se crea una instancia que representa la lambda de manera sensible, depende del contenido exacto del cuerpo de la lambda. A saber, el factor clave es lo que captura la lambda del entorno léxico. Si no captura ningún estado que sea variable de una creación a otra, entonces no se creará una instancia cada vez que se ingrese el ciclo for-each. En cambio, se generará un método sintético en el momento de la compilación y el sitio de uso lambda solo recibirá un objeto singleton que delega a ese método.
Además, tenga en cuenta que este aspecto depende de la implementación y puede esperar futuros refinamientos y avances en HotSpot hacia una mayor eficiencia. Hay planes generales para, por ejemplo, hacer un objeto liviano sin una clase correspondiente completa, que tenga suficiente información para reenviar a un solo método.
Aquí hay un buen artículo accesible en profundidad sobre el tema:
http://www.infoq.com/articles/Java-8-Lambdas-A-Peek-Under-the-Hood
fuente
Está pasando una nueva instancia al
forEach
método. Cada vez que haces eso, creas un nuevo objeto pero no uno para cada iteración de bucle. La iteración se realiza dentro delforEach
método utilizando la misma instancia de objeto 'devolución de llamada' hasta que se realiza con el bucle.Por lo tanto, la memoria utilizada por el bucle no depende del tamaño de la colección.
Si. Tiene ligeras diferencias a un nivel muy bajo, pero no creo que debas preocuparte por ellas. Las expresiones de Lamba utilizan la función invocada dinámica en lugar de clases anónimas.
fuente