Notice: This page requires JavaScript to function properly.
Please enable JavaScript in your browser settings or update your browser.
Aprende Principios | Fundamentos y Capacidades Funcionales de Stream API
Stream API

bookPrincipios

Los principios de trabajo con la Stream API se basan en conceptos clave de la programación funcional y la evaluación perezosa. A continuación, se presentan los principales principios de la Stream API.

Evaluación Perezosa

Uno de los principios fundamentales de la Stream API es la evaluación perezosa.

Esto significa que las operaciones intermedias como filter() o map() no se ejecutan de inmediato. Simplemente forman una cadena de acciones que se ejecutarán únicamente cuando se invoque una operación terminal, como collect() o forEach().

Main.java

Main.java

copy
12345678910111213
package com.example; import java.util.List; public class Main { public static void main(String[] args) { List<String> names = List.of("Alice", "Bob", "Charlie"); long count = names.stream() .filter(name -> name.startsWith("A")) // Forming the operation .count(); // Triggering execution System.out.println(count); // Output: 1 } }

Este código crea un stream a partir de una lista de cadenas, filtra los elementos para conservar solo aquellos que comienzan con la letra A, y cuenta cuántos cumplen la condición. Se imprime el resultado (1), ya que solo Alice satisface la condición.

Estilo de Programación Funcional

La Stream API utiliza expresiones lambda e interfaces funcionales para el procesamiento de datos. En lugar del enfoque imperativo con bucles, se describe lo que se debe hacer con los datos:

Main.java

Main.java

copy
1234567891011121314
package com.example; import java.util.List; public class Main { public static void main(String[] args) { List<String> fruits = List.of("apple", "banana", "cherry", "apricot", "blueberry"); List<String> result = fruits.stream() .map(String::toUpperCase) // Convert all strings to uppercase .skip(3) .toList(); // Collect the result into a new list System.out.println(result); } }

Este código crea un stream a partir de una lista de frutas, convierte las cadenas a mayúsculas usando map(), y omite los primeros tres elementos con skip(). El resultado se recopila en una nueva lista y se imprime, comenzando desde el cuarto elemento.

Inmutabilidad de los datos

La Stream API no modifica los datos originales. Todas las operaciones crean un nuevo stream o devuelven un resultado sin modificar la colección o el arreglo. Esto mejora la seguridad de los datos y previene efectos secundarios inesperados.

Main.java

Main.java

copy
12345678910111213
package com.example; import java.util.List; public class Main { public static void main(String[] args) { List<String> names = List.of("Alice", "Bob", "Charlie"); List<String> updateNames = names.stream() .filter(name -> name.startsWith("A")) .toList(); System.out.println(names); // Output: [Alice, Bob, Charlie] } }

La Stream API filtra la lista names para crear un nuevo stream, updateNames, que contiene solo los elementos que comienzan con la letra A. Sin embargo, la lista original names permanece sin cambios, ya que la Stream API no modifica los datos directamente, garantizando la seguridad de los datos y previniendo efectos secundarios.

Los Streams Son Consumibles Una Sola Vez

Un stream puede ser utilizado solo una vez. Después de realizar una operación terminal, el stream queda indisponible para un procesamiento posterior.

Main.java

Main.java

copy
123456789101112
package com.example; import java.util.List; import java.util.stream.Stream; public class Main { public static void main(String[] args) { Stream<String> stream = List.of("Alice", "Bob").stream(); stream.forEach(System.out::println); stream.forEach(System.out::println); // Error: Stream has already been used } }

Aquí, se crea un stream a partir de una lista de cadenas y se imprime cada elemento en la consola. Después de que el stream se utiliza por primera vez, no puede ser reutilizado, lo que provoca un error si se intenta llamar a forEach() nuevamente.

Procesamiento paralelo

La Stream API admite streams paralelos, lo que permite un procesamiento de datos más rápido en sistemas multinúcleo. Esto se explora en mayor detalle aquí

Main.java

Main.java

copy
1234567891011
package com.example; import java.util.List; public class Main { public static void main(String[] args) { List<Integer> numbers = List.of(1, 2, 3, 4, 5); numbers.parallelStream() .forEach(System.out::println); // Elements are processed in parallel } }

Este código crea un stream paralelo a partir de una lista de números y muestra cada elemento en la consola. El uso de parallelStream() permite el procesamiento paralelo de los elementos de la lista, lo que puede acelerar la ejecución al trabajar con conjuntos de datos grandes.

Limpieza y legibilidad del código

El uso de la Stream API hace que el código sea más declarativo. En lugar de describir cómo realizar una tarea (como usar bucles), se describe qué se necesita hacer exactamente. Esto mejora la legibilidad y simplifica el mantenimiento del código.

Ejemplo con un bucle:

List<String> names = List.of("Alice", "Bob", "Charlie");
for (String name : names) {
    System.out.println(name);
}

Ejemplo usando Stream API:

List<String> names = List.of("Alice", "Bob", "Charlie");
names.stream().forEach(System.out::println);

En el primer ejemplo de bucle, se describe explícitamente cómo iterar a través de la lista e imprimir los elementos, mientras que en el segundo ejemplo con Stream API, simplemente se especifica qué se debe hacer: iterar por los elementos e imprimirlos. Esto hace que el código sea más declarativo y legible.

¿Todo estuvo claro?

¿Cómo podemos mejorarlo?

¡Gracias por tus comentarios!

Sección 1. Capítulo 2

Pregunte a AI

expand

Pregunte a AI

ChatGPT

Pregunte lo que quiera o pruebe una de las preguntas sugeridas para comenzar nuestra charla

Suggested prompts:

Can you explain more about lazy evaluation in the Stream API?

What are some common terminal and intermediate operations in streams?

How does the Stream API improve code readability compared to traditional loops?

Awesome!

Completion rate improved to 2.33

bookPrincipios

Desliza para mostrar el menú

Los principios de trabajo con la Stream API se basan en conceptos clave de la programación funcional y la evaluación perezosa. A continuación, se presentan los principales principios de la Stream API.

Evaluación Perezosa

Uno de los principios fundamentales de la Stream API es la evaluación perezosa.

Esto significa que las operaciones intermedias como filter() o map() no se ejecutan de inmediato. Simplemente forman una cadena de acciones que se ejecutarán únicamente cuando se invoque una operación terminal, como collect() o forEach().

Main.java

Main.java

copy
12345678910111213
package com.example; import java.util.List; public class Main { public static void main(String[] args) { List<String> names = List.of("Alice", "Bob", "Charlie"); long count = names.stream() .filter(name -> name.startsWith("A")) // Forming the operation .count(); // Triggering execution System.out.println(count); // Output: 1 } }

Este código crea un stream a partir de una lista de cadenas, filtra los elementos para conservar solo aquellos que comienzan con la letra A, y cuenta cuántos cumplen la condición. Se imprime el resultado (1), ya que solo Alice satisface la condición.

Estilo de Programación Funcional

La Stream API utiliza expresiones lambda e interfaces funcionales para el procesamiento de datos. En lugar del enfoque imperativo con bucles, se describe lo que se debe hacer con los datos:

Main.java

Main.java

copy
1234567891011121314
package com.example; import java.util.List; public class Main { public static void main(String[] args) { List<String> fruits = List.of("apple", "banana", "cherry", "apricot", "blueberry"); List<String> result = fruits.stream() .map(String::toUpperCase) // Convert all strings to uppercase .skip(3) .toList(); // Collect the result into a new list System.out.println(result); } }

Este código crea un stream a partir de una lista de frutas, convierte las cadenas a mayúsculas usando map(), y omite los primeros tres elementos con skip(). El resultado se recopila en una nueva lista y se imprime, comenzando desde el cuarto elemento.

Inmutabilidad de los datos

La Stream API no modifica los datos originales. Todas las operaciones crean un nuevo stream o devuelven un resultado sin modificar la colección o el arreglo. Esto mejora la seguridad de los datos y previene efectos secundarios inesperados.

Main.java

Main.java

copy
12345678910111213
package com.example; import java.util.List; public class Main { public static void main(String[] args) { List<String> names = List.of("Alice", "Bob", "Charlie"); List<String> updateNames = names.stream() .filter(name -> name.startsWith("A")) .toList(); System.out.println(names); // Output: [Alice, Bob, Charlie] } }

La Stream API filtra la lista names para crear un nuevo stream, updateNames, que contiene solo los elementos que comienzan con la letra A. Sin embargo, la lista original names permanece sin cambios, ya que la Stream API no modifica los datos directamente, garantizando la seguridad de los datos y previniendo efectos secundarios.

Los Streams Son Consumibles Una Sola Vez

Un stream puede ser utilizado solo una vez. Después de realizar una operación terminal, el stream queda indisponible para un procesamiento posterior.

Main.java

Main.java

copy
123456789101112
package com.example; import java.util.List; import java.util.stream.Stream; public class Main { public static void main(String[] args) { Stream<String> stream = List.of("Alice", "Bob").stream(); stream.forEach(System.out::println); stream.forEach(System.out::println); // Error: Stream has already been used } }

Aquí, se crea un stream a partir de una lista de cadenas y se imprime cada elemento en la consola. Después de que el stream se utiliza por primera vez, no puede ser reutilizado, lo que provoca un error si se intenta llamar a forEach() nuevamente.

Procesamiento paralelo

La Stream API admite streams paralelos, lo que permite un procesamiento de datos más rápido en sistemas multinúcleo. Esto se explora en mayor detalle aquí

Main.java

Main.java

copy
1234567891011
package com.example; import java.util.List; public class Main { public static void main(String[] args) { List<Integer> numbers = List.of(1, 2, 3, 4, 5); numbers.parallelStream() .forEach(System.out::println); // Elements are processed in parallel } }

Este código crea un stream paralelo a partir de una lista de números y muestra cada elemento en la consola. El uso de parallelStream() permite el procesamiento paralelo de los elementos de la lista, lo que puede acelerar la ejecución al trabajar con conjuntos de datos grandes.

Limpieza y legibilidad del código

El uso de la Stream API hace que el código sea más declarativo. En lugar de describir cómo realizar una tarea (como usar bucles), se describe qué se necesita hacer exactamente. Esto mejora la legibilidad y simplifica el mantenimiento del código.

Ejemplo con un bucle:

List<String> names = List.of("Alice", "Bob", "Charlie");
for (String name : names) {
    System.out.println(name);
}

Ejemplo usando Stream API:

List<String> names = List.of("Alice", "Bob", "Charlie");
names.stream().forEach(System.out::println);

En el primer ejemplo de bucle, se describe explícitamente cómo iterar a través de la lista e imprimir los elementos, mientras que en el segundo ejemplo con Stream API, simplemente se especifica qué se debe hacer: iterar por los elementos e imprimirlos. Esto hace que el código sea más declarativo y legible.

¿Todo estuvo claro?

¿Cómo podemos mejorarlo?

¡Gracias por tus comentarios!

Sección 1. Capítulo 2
some-alt