Buscar
Social
Ofertas laborales ES

Foro sobre Java SE > Streams de Java 8

Hola gente.

Estoy probando Java 8 y he visto ciertas mejoras acojonantes.
La mayor parte de la gente si fija en las closures, que ciertamente a veces simplifican el código, pero en muchos casos me parece mas difícil de leer..

Lo primero que me ha encantado es la nueva librería de Date/Time. Ya tocaba algo mejor pensado.

Lo segundo, que me estoy mirando ahora, son los stream de las colecciones, predicados y funciones. Me parece un avance muy considerable y una forma comodísima de aplicar operaciones sobre recorridos.
¿Que os parecen ?
Por cierto, ¿Alguien ha comparado tiempos entre el recorrido ordinario de las colecciones y el nuevo manejo por streams? Mas simple lo parece, pero falta saber si es mas eficiente.

Un saludo

abril 5, 2014 | Unregistered CommenterPaposo

En una búsqueda rápida solo he encontrado un cutre-microbenchmark en stackoverflow: http://stackoverflow.com/questions/21968918/java-8-nested-loops-with-streams-performance

Para mi lo increiblemente potente, aparte de la sintaxis, es que permite hacer paralelismo en operaciones filter-map-reduce sobre colecciones de forma casi trivial.
Esto, trabajando con conjuntos de datos amplios y teniendo en cuenta por donde va la evolución del hardware actual, debería implicar unas inmensas mejoras en el rendimiento de ciertas aplicaciones. http://docs.oracle.com/javase/tutorial/collections/streams/parallelism.html

Un saludo

abril 5, 2014 | Unregistered CommenterUnoPorAhi

Sigue un test que he adaptado de una comparación con PLINQ.
Puede tardar varios minutos en completarse.
En mi sistema (4 núcleos), el promedio para ejecución en serie es de 391, mientras que en paralelo es de 119. Esa diferencia de casi 4 veces menor para el paralelo, se explica por la partición del Fork/Join entre los núcleos disponibles.

public class Test {

public static final int ejecuciones = 100;

public static void main(String[] args) {

double[] valoresAleatorios = DoubleStream.generate(new Random()::nextDouble).limit(10_000_000).toArray();

System.out.println("precalentamiento iniciado");
for (int i = 0; i < ejecuciones; i++) {
Arrays.stream(valoresAleatorios).map(Math::sin).toArray();
}
for (int i = 0; i < ejecuciones; i++) {
Arrays.stream(valoresAleatorios).parallel().map(Math::sin).toArray();
}
System.out.println("precalentamiento terminado");

double promedio = 0.0;
System.out.println("Serie:");
for (int i = 0; i < ejecuciones; i++) {
long inicio = System.nanoTime();
Arrays.stream(valoresAleatorios).map(Math::sin).toArray();
double duracion = (System.nanoTime() - inicio) / 1_000_000.0;
System.out.print(duracion + ", ");
if (i > 0) {
promedio += duracion;
}
}
System.out.println("\nPromedio:" + (promedio / (ejecuciones - 1)));

promedio = 0.0;
System.out.println("\n\nParalelo:");
for (int i = 0; i < ejecuciones; i++) {
long inicio = System.nanoTime();
Arrays.stream(valoresAleatorios).parallel().map(Math::sin).toArray();
double duracion = (System.nanoTime() - inicio) / 1_000_000.0;
System.out.print(duracion + ", ");
if (i > 0) {
promedio += duracion;
}
}
System.out.println("\nPromedio:" + (promedio / (ejecuciones - 1)));
}
}

abril 5, 2014 | Registered Commenterchoces

Ahí está. Impresionante

abril 5, 2014 | Unregistered CommenterUnoPorAhi

Este nuevo test que he preparado, quizá muestre las diferencias con más claridad, porque incluye el método habitual anterior a JavaSE 1.8 para recorrer una colección.

Los tiempos obtenidos son:

tiempo suma 1.7 = 15072
tiempo suma 1.8 = 14824
tiempo suma paralela 1.8 = 4270


import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.Random;

public class Test {

public static void main(String[] args) {

Random random = new Random();
List<Integer> listaEnteros = new ArrayList<>(100_000);
for (int i = 0; i < 100_000; i++) {
listaEnteros.add(random.nextInt());
}

System.out.println("precalentamiento iniciado");
for (int i = 0; i < 10_000; i++) {
Integer suma = 0;
for (Integer entero : listaEnteros) {
suma += entero;
}
suma = 0;
suma = listaEnteros.stream().map((Integer entero) -> {
return entero;
}).reduce(suma, Integer::sum);
suma = 0;
suma = listaEnteros.stream().parallel().map((Integer entero) -> {
return entero;
}).reduce(suma, Integer::sum);
}
System.out.println("precalentamiento terminado");

System.out.println("suma 1.7 iniciada");
long inicio1 = System.currentTimeMillis();
for (int i = 0; i < 10_000; i++) {
Integer suma = 0;
for (Iterator<Integer> it = listaEnteros.iterator(); it.hasNext();) {
suma += it.next();
}
}
System.out.println("tiempo suma 1.7 = " + (System.currentTimeMillis() - inicio1));

System.out.println("suma 1.8 iniciada");
long inicio2 = System.currentTimeMillis();
for (int i = 0; i < 10_000; i++) {
Integer suma = 0;
suma = listaEnteros.stream().map((Integer entero) -> {
return entero;
}).reduce(suma, Integer::sum);
}
System.out.println("tiempo suma 1.8 = " + (System.currentTimeMillis() - inicio2));

System.out.println("suma paralela 1.8 iniciada");
long inicio3 = System.currentTimeMillis();
for (int i = 0; i < 10_000; i++) {
Integer suma = 0;
suma = listaEnteros.stream().parallel().map((Integer entero) -> {
return entero;
}).reduce(suma, Integer::sum);
}
System.out.println("tiempo suma paralela 1.8 = " + (System.currentTimeMillis() - inicio3));
}
}

abril 5, 2014 | Registered Commenterchoces