Podemos definir Streams como una secuencia de funciones que se ejecutan una detrás de otra, de forma anidada.
Comparemos antes un Iterador con un Stream. Habitualmente cuando tenemos una collection lo que hacemos luego es iterar para realizar algo con dicha colección.
Un Stream luce similar a una collection permitiendo además realizar operaciones directamente sobre el Stream. Cada operación devuelve un nuevo stream sobre el cual podemos seguir encadenando otras operaciones.
String einstein = "La imaginación es más importante que el conocimiento";
String[] splited = einstein.split("\\s+");
// Collection to Iterate
List<String> words = Arrays.asList(splited);
int count = 0;
for(String w : words) {
if(w.startsWith("i")) {
count++;
}
}
// JAVA 8
words.stream().filter(w -> w.startsWith("i")).count();
Las operaciones sobre Stream pueden ser intermedias o finales. En el caso de ser intermedias (filter, sorted, map) stream devolverá nuevamente otro stream permitiendo la continuidad de pasos o funciones sobre ella misma. Esto es llamado ‘pipelining’.
In computing, a pipeline is a set of data processing elements connected in series, where the output of one element is the input of the next one. The elements of a pipeline are often executed in parallel or in time-sliced fashion; in that case, some amount of buffer storage is often inserted between elements.
Estas son algunas funciones intermedias:
// Intermediate operations
Stream<Product> stream = products.stream();
Stream<Product> filterStream = stream.filter(p -> "B".equals(p.getType()));
Stream<Product> sorted = filterStream.sorted(comparing(Product::getPrice));
// Final operation
sorted.forEach(System.out::println);
Si no has leido sobre Lamndas te recomiendo una breve lectura antes.
Supongamos que quieres procesar una lista de productos y realizar diferentes procesos como:
- recorrer la lista
- filtrar durante el recorrido los elementos según alguna condición
- ordenar el resultado anterior
- mostrar el resultado
Harías estas operaciones de forma tradicional así:
List<Product> products = getProducts();
List<Product> resultFilter = new ArrayList<>();
// foreach filter
for(Product p : products) {
if("B".equals(p.getType())){
resultFilter.add(p);
}
}
// sort
Collections.sort(resultFilter, new Comparator<Product>() {
@Override
public int compare(Product p1, Product p2) {
return p1.getPrice().compareTo(p2.getPrice());
}
});
// print
for(Product p: resultFilter) {
System.out.println(p);
}
La clase Product que usas es:
public class Product {
private long id;
private String name;
private String type;
private Double price;
// get and set...
}
Como usar Stream con Java 8
Con Java 8 utilizando Streams y Lambdas haces las mismas operaciones anteriores de este modo:
List<Product> products = getProducts();
// filter + sort + print
products.stream().filter(p ->"B".equals(p.getType())).
sorted(comparing(Product::getPrice)).
forEach(System.out::println);
Puedes observar rápidamente la reducción en líneas de código y complejidad con este simple ejemplo.
Ejemplos de uso simple Stream con Java 8
Observa esta operaciones usando Stream y como pueden ayudarte
List<Product> products = getProducts();
// limit and foreach
products.stream().limit(10).forEach(System.out::println);
// filter and count
long count = products.stream().filter(product -> product.getPrice() > 200d).count();
System.out.println(count);
// collect ids
List<Long> ids = products.stream().filter(product -> product.getPrice() > 200d).
map(p -> p.getId()).collect(Collectors.toList());
ids.forEach(System.out::print); // print this ids..
//statistics
DoubleSummaryStatistics doubleSummaryStatistics = products.stream().mapToDouble(p -> p.getPrice()).summaryStatistics();
System.out.println(doubleSummaryStatistics.getSum());
System.out.println(doubleSummaryStatistics.getMax());
System.out.println(doubleSummaryStatistics.getMin());
Referencias: [http://www.oracle.com/technetwork/articles/java/ma14-java-se-8-streams-2177646.html]3
…