Saltar al contenido

Java 8 Streams: filtros múltiples frente a condiciones complejas

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:
10 elemento array

Para operaciones/s de rendimiento medio de 10 000 elementos:
ingrese la descripción de la imagen aquí
Para grande array 1.000.000 elementos de rendimiento de operaciones/s:
1M elementos

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
Java 8vs11

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.

¡Haz clic para puntuar esta entrada!
(Votos: 0 Promedio: 0)



Utiliza Nuestro Buscador

Deja una respuesta

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *