Hace ya bastante tiempo que JDK 8 está en la calle, pero muchas veces surgen dudas de las nuevas funcionalidades que podemos encontrarnos en cada nueva versión.
Sobre todo para aquellos desarrolladores y compañeros de profesión que solo ven nuevas versiones, como nuevas opciones que hacen funcionar las cosas por arte de magia, pero nada más lejos de la realidad.
Por tanto, dentro de este artículo vamos a analizar la funcionalidad del Stream API en Java 8. También veremos cómo crear y utilizar streams en acción. Y además la diferencia de rendimiento que se produce con su uso, algo que cuando hablamos en un mundo gobernado por millones de datos, se hace más que interesante.
Vamos!
Entorno
Para la realización del ejercicio se ha utilizado el siguiente entorno:
- Hardware: Portatil MSI Prestige 15 (Intel Core 11th Gen 4 CPU 3 GHz, 32 GB Ram)
- SO: Windows 11 Pro
- Entorno de desarollo: VSCode
- Wsl2 con Ubuntu 20.04.6 LTS (Focal Fossa)
- Java 17
- Maven 3.9.x
¿Qué son los Streams?
Como hemos comentado el API de Stream en Java se agregó en JDK 8 para proporcionar un enfoque funcional para procesar una colección de objetos. El Stream de Java no almacena datos y no es una estructura de datos. Además, el origen de datos subyacente no se modifica.
El Stream de Java utiliza interfaces funcionales y admite operaciones en estilo funcional en flujos de elementos mediante el uso de expresiones lambda.
Los Streams de Java 8 son un envoltorío alrededor de un origen de datos (Array, List, etc.) que nos permite operar con la fuente de datos y realizar un procesamiento en bloque de manera rápida y conveniente.
Es un flujo de datos que procesa los datos desde la fuente original y envía los datos procesados a la fuente de datos de destino.
Definición de la API
Configuración del entorno
Creamos un proyecto maven.
Para este objetivo sencillo usamos el propio arquetipo que nos proporciona Maven, descrito aqui:
Gist Maven
$ mvn archetype:generate | |
-DgroupId=com.mrknight.streams1 | |
-DartifactId=tutorial | |
-DarchetypeArtifactId=maven-archetype-quickstart | |
-DinteractiveMode=false | |
$ cd tutorial | |
$ mvn clean package | |
$ java -cp target/tutorial-1.0-SNAPSHOT.jar com.mrknight.streams1.App |
<project xmlns="http://maven.apache.org/POM/4.0.0" | |
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" | |
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd"> | |
<modelVersion>4.0.0</modelVersion> | |
<groupId>com.mrknight.streams1</groupId> | |
<artifactId>tutorial</artifactId> | |
<packaging>jar</packaging> | |
<version>1.0-SNAPSHOT</version> | |
<name>tutorial</name> | |
<url>http://maven.apache.org</url> | |
<dependencies> | |
<dependency> | |
<groupId>junit</groupId> | |
<artifactId>junit</artifactId> | |
<version>3.8.1</version> | |
<scope>test</scope> | |
</dependency> | |
<dependency> | |
<groupId>org.projectlombok</groupId> | |
<artifactId>lombok</artifactId> | |
<version>1.18.28</version> | |
</dependency> | |
</dependencies> | |
<build> | |
<plugins> | |
<plugin> | |
<groupId>org.codehaus.mojo</groupId> | |
<artifactId>exec-maven-plugin</artifactId> | |
<version>3.1.0</version> | |
<configuration> | |
<mainClass>com.mrknight.streams1.App</mainClass> | |
</configuration> | |
</plugin> | |
</plugins> | |
</build> | |
</project> |
Manos la obra
public Stream<String> createStreamFromArray() { | |
String[] strArr = { "Val1", "Demo2", "Val3", "Demo4", "Val3", "Demo4" }; | |
return Arrays.stream(strArr); | |
} |
Operaciones
- Intermediate operations. Aquellas que devuelven un new Stream. Son operaciones que son enviadas a la siguiente operacion normalmente. Ejemplos:
- filter()
- map()
- flatMap()
- distinct()
- sorted()
- peek()
- limit()
- skip()
- Terminal operations. Aquellas que NO devuelven un new Stream. Son operaciones que una vez que las llamamos, el Stream se consume y por tanto no pueden ser enviadas a la siguiente operacion. Ejemplos:
- toArray()
- collect()
- count()
- reduce()
- forEach()
- forEachOrdered()
- min()
- max()
- anyMatch()
- allMatch()
- noneMatch()
- findAny()
- findFirst()
public class DemoService1 { | |
public Stream<String> createStreamFromArray() { | |
String[] strArr = { "Val1", "Demo2", "Val3", "Demo4", "Val3", "Demo4" }; | |
return Arrays.stream(strArr); | |
} | |
public Stream<Item> createStreamFromEntity() { | |
Item f1 = new Item("Item 1", 3000); | |
Item f2 = new Item("Item 2", 1000); | |
Item f3 = new Item("Item 3", 300); | |
Item f4 = new Item("Item 4", 2000); | |
List<Item> lItem = new ArrayList<Item>(); | |
lItem.add(f1); | |
lItem.add(f2); | |
lItem.add(f3); | |
lItem.add(f4); | |
return lItem.stream(); | |
} | |
} |
DemoService1 svc1 = new DemoService1(); | |
// Some Stream operations | |
System.out.println("\n **** Intermediate Operations ****\n"); | |
// Filter stream | |
System.out.println("*** Filter ***"); | |
svc1.createStreamFromArray().filter(s -> s.startsWith("V")).forEach(System.out::println); | |
// Map: new stream applying the function to each element | |
System.out.println("*** Map ***"); | |
svc1.createStreamFromArray().map(s -> s.toUpperCase()).forEach(System.out::println); | |
// Distinct: Return stream with only unique elements | |
System.out.println("*** Distinct ***"); | |
svc1.createStreamFromArray().distinct().forEach(System.out::println); | |
// Sorted: Return stream sorted according natural order | |
System.out.println("*** Sorted ***"); | |
svc1.createStreamFromArray().sorted().forEach(System.out::println); | |
// Some Stream Terminals operations | |
System.out.println("\n **** Terminals Operations ****\n"); | |
// FindFirst: Return a Optional for de FIRST entry in the Stream | |
System.out.println("*** FindFirst ***"); | |
System.out.println("\n\nItems filtradas: " + svc1.createStreamFromEntity() | |
.filter(f -> f.getImporte() > 1000) | |
.findFirst() | |
.get() | |
.getImporte()); | |
// FindAny: Return a Optional for ANY entry in the Stream | |
System.out.println("*** FindAny ***"); | |
System.out.println("\n\nFind any: " + svc1.createStreamFromEntity() | |
.filter(f -> f.getImporte() > 100) | |
.findAny() | |
.get() | |
.getImporte()); | |
// Peek: Perform the specified op on EACH elem an return NEW STREAM. Normally is | |
// used to debug. | |
System.out.println("*** Peek ***"); | |
svc1.createStreamFromEntity() | |
.map(f -> f.getImporte() * 10) | |
.peek(System.out::println) | |
.collect(Collectors.toList()); | |
System.out | |
.println("*** Stream not modify source ***:: " + svc1.createStreamFromArray().collect(Collectors.toList())); |
Rendimiento
// FindFirst: Return a Optional for de FIRST entry in the Stream | |
System.out.println("*** FindFirst ***"); | |
System.out.println("\n\nItems filtradas: " + svc1.createStreamFromEntity() | |
.filter(f -> f.getImporte() > 100) | |
.peek(System.out::println) | |
.findFirst() | |
.get() | |
.getImporte()); |
No hay comentarios:
Publicar un comentario
Nota: solo los miembros de este blog pueden publicar comentarios.