Ya no necesitas investigar más en otras páginas ya que estás al espacio correcto, contamos con la respuesta que quieres encontrar pero sin complicarte.
Solución:
El código que debe ejecutarse para ambas alternativas es tan similar que no se puede predecir un resultado de forma fiable. 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 ambientales 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étodos en lugar de expresiones lambda, por ejemplo, reemplazar filter(x -> x.isCool())
por filter(ItemType::isCool)
. De esa manera, ha eliminado el método de delegación sintético creado para su expresión lambda. Por lo tanto, la combinación de dos filtros con dos referencias de métodos podría crear el mismo código de delegación o uno menor que uno solo. filter
invocación usando una expresión lambda con &&
.
Pero, como se dijo, este tipo de sobrecarga será eliminada por el optimizador HotSpot y es insignificante.
En teoría, dos filtros podrían ser más fáciles de paralelizar que un solo filtro, pero eso solo es relevante para tareas computacionales bastante intensas¹.
Así que no hay una respuesta simple.
La conclusión es que no piense en tales 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 hiciera un procesamiento paralelo de las etapas subsiguientes, un camino que actualmente no sigue la implementación estándar de Stream
Una condición de filtro compleja es mejor desde el punto de vista del rendimiento, pero el mejor rendimiento se mostrará a la antigua con un bucle estándar. if clause
es la mejor opción. La diferencia en un pequeño array La diferencia de 10 elementos podría ~ 2 veces, para una gran array la diferencia no es tan grande.
Puede echar un vistazo a mi proyecto de GitHub, donde realicé pruebas de rendimiento para múltiples array opciones de iteración
Para pequeños array Operaciones de rendimiento de 10 elementos/s:
Para operaciones/s de rendimiento medio de 10 000 elementos:
Para grande array 1.000.000 elementos de rendimiento de operaciones/s:
NOTA: las pruebas se ejecutan en
- 8 procesadores
- 1GB RAM
- Versión del sistema operativo: 16.04.1 LTS (Xenial Xerus)
- versión java: 1.8.0_121
- jvm: -XX:+UsarG1GC -servidor -Xmx1024m -Xms1024m
ACTUALIZAR:
Java 11 tiene algunos avances en el rendimiento, pero la dinámica sigue siendo la misma
Modo de referencia: rendimiento, operaciones/tiempo
Esta prueba muestra que su segunda opción puede funcionar significativamente mejor. Hallazgos primero, luego el código:
one filter with predicate of form u -> exp1 && exp2, list size 10000000, averaged over 100 runs: LongSummaryStatisticscount=100, sum=4142, min=29, average=41.420000, max=82
two filters with predicates of form u -> exp1, list size 10000000, averaged over 100 runs: LongSummaryStatisticscount=100, sum=13315, min=117, average=133.150000, max=153
one filter with predicate of form predOne.and(pred2), list size 10000000, averaged over 100 runs: LongSummaryStatisticscount=100, sum=10320, min=82, average=103.200000, max=127
ahora el codigo:
enum Gender
FEMALE,
MALE
static class User
Gender gender;
int age;
public User(Gender gender, int age)
this.gender = gender;
this.age = age;
public Gender getGender()
return gender;
public void setGender(Gender gender)
this.gender = gender;
public int getAge()
return age;
public void setAge(int age)
this.age = age;
static long test1(List users)
long time1 = System.currentTimeMillis();
users.stream()
.filter((u) -> u.getGender() == Gender.FEMALE && u.getAge() % 2 == 0)
.allMatch(u -> true); // least overhead terminal function I can think of
long time2 = System.currentTimeMillis();
return time2 - time1;
static long test2(List users)
long time1 = System.currentTimeMillis();
users.stream()
.filter(u -> u.getGender() == Gender.FEMALE)
.filter(u -> u.getAge() % 2 == 0)
.allMatch(u -> true); // least overhead terminal function I can think of
long time2 = System.currentTimeMillis();
return time2 - time1;
static long test3(List users)
long time1 = System.currentTimeMillis();
users.stream()
.filter(((Predicate) u -> u.getGender() == Gender.FEMALE).and(u -> u.getAge() % 2 == 0))
.allMatch(u -> true); // least overhead terminal function I can think of
long time2 = System.currentTimeMillis();
return time2 - time1;
public static void main(String... args)
int size = 10000000;
List users =
IntStream.range(0,size)
.mapToObj(i -> i % 2 == 0 ? new User(Gender.MALE, i % 100) : new User(Gender.FEMALE, i % 100))
.collect(Collectors.toCollection(()->new ArrayList<>(size)));
repeat("one filter with predicate of form u -> exp1 && exp2", users, Temp::test1, 100);
repeat("two filters with predicates of form u -> exp1", users, Temp::test2, 100);
repeat("one filter with predicate of form predOne.and(pred2)", users, Temp::test3, 100);
private static void repeat(String name, List users, ToLongFunction> test, int iterations)
System.out.println(name + ", list size " + users.size() + ", averaged over " + iterations + " runs: " + IntStream.range(0, iterations)
.mapToLong(i -> test.applyAsLong(users))
.summaryStatistics());
Si eres capaz, tienes el poder dejar una sección acerca de qué te ha parecido este ensayo.