A veces desea filtrar un Stream
con más de una condición:
myList.stream().filter(x -> x.size() > 10).filter(x -> x.isCool()) ...
o podría hacer lo mismo con una condición compleja y una sola filter
:
myList.stream().filter(x -> x.size() > 10 && x -> x.isCool()) ...
Supongo que el segundo enfoque tiene mejores características de rendimiento, pero no lo sé .
El primer enfoque gana en legibilidad, pero ¿qué es mejor para el rendimiento?
Respuestas:
El código que debe ejecutarse para ambas alternativas es tan similar que no puede predecir un resultado de manera confiable. La estructura del objeto subyacente puede diferir, pero eso no es un desafío para el optimizador de puntos de acceso. Por lo tanto, depende de otras condiciones circundantes que darán lugar a una ejecución más rápida, si hay alguna diferencia.
La combinación de dos instancias de filtro crea más objetos y, por lo tanto, más código de delegación, pero esto puede cambiar si usa referencias de método en lugar de expresiones lambda, por ejemplo, reemplazar
filter(x -> x.isCool())
porfilter(ItemType::isCool)
. De esa manera, ha eliminado el método de delegación sintético creado para su expresión lambda. Por lo tanto, combinar dos filtros usando dos referencias de método podría crear el mismo código de delegación o menor que una solafilter
invocación usando una expresión lambda con&&
.Pero, como se dijo, este tipo de sobrecarga será eliminado por el optimizador de HotSpot y es insignificante.
En teoría, dos filtros podrían ser paralelizados más fácilmente que un solo filtro, pero eso solo es relevante para tareas intensas computacionales¹.
Entonces no hay una respuesta simple.
La conclusión es que no piense en esas diferencias de rendimiento por debajo del umbral de detección de olores. Usa lo que sea más legible.
¹ ... y requeriría una implementación que realice el procesamiento paralelo de las etapas posteriores, un camino que actualmente no es tomado por la implementación estándar de Stream
fuente
Una condición de filtro compleja es mejor en la perspectiva de rendimiento, pero el mejor rendimiento mostrará que
if clause
la opción más antigua es un bucle con un estándar . La diferencia en una matriz pequeña de 10 elementos puede ser ~ 2 veces, para una matriz grande la diferencia no es tan grande.Puedes echar un vistazo a mi proyecto GitHub , donde hice pruebas de rendimiento para múltiples opciones de iteración de matriz
Para operaciones de rendimiento de 10 elementos de una matriz pequeña: Para operaciones de rendimiento medio de 10,000 elementos / s: Para operaciones de producción de 1,000,000 elementos de una matriz grande:
NOTA: las pruebas se ejecutan en
ACTUALIZACIÓN: Java 11 tiene cierto progreso en el rendimiento, pero la dinámica se mantiene igual
Modo de referencia: rendimiento, operaciones / tiempo
fuente
Esta prueba muestra que su segunda opción puede funcionar significativamente mejor. Primero los hallazgos, luego el código:
ahora el código:
fuente
Test #1: {count=100, sum=7207, min=65, average=72.070000, max=91} Test #3: {count=100, sum=7959, min=72, average=79.590000, max=97} Test #2: {count=100, sum=8869, min=79, average=88.690000, max=110}
Este es el resultado de las 6 combinaciones diferentes de la prueba de muestra compartida por @Hank D Es evidente que el predicado de la forma
u -> exp1 && exp2
es altamente eficiente en todos los casos.fuente