Java
Tutorial Java: Creación de Streams
Java streams: procesamiento de datos eficiente. Domina el procesamiento de datos en Java utilizando streams con ejemplos prácticos.
Aprende Java GRATIS y certifícateLos "Streams" en Java SE son una característica introducida en Java 8 y se enmarcan dentro del paradigma de la programación funcional. Son una nueva abstracción que permite trabajar con datos de una manera más declarativa. Están diseñados para procesar grandes cantidades de datos de manera eficiente, incluso aprovechando la arquitectura multi-core de los modernos sistemas de cómputo.
En términos sencillos, un Stream en Java es una secuencia de datos. Un Stream toma una colección de datos como entrada y permite realizar operaciones en dichos datos, como transformaciones y agregaciones. Los Streams son "lazy", es decir, no se ejecutan hasta que se necesita el resultado. Esto permite que las operaciones de Stream sean muy eficientes, ya que no se realizan cálculos innecesarios.
A continuación, se presentará cómo crear y utilizar Streams en Java SE. Para comenzar, es importante entender cómo se crean los Streams.
Creación de Streams
La creación de un Stream se puede realizar de varias maneras. La más común es a partir de una colección de datos. Todas las clases que implementan la interfaz java.util.Collection
, como ArrayList
, HashSet
y LinkedList
, tienen un método stream()
que permite crear un Stream.
Aquí se muestra un ejemplo de cómo crear un Stream a partir de una lista:
List<String> list = Arrays.asList("a", "b", "c");
Stream<String> stream = list.stream();
Se puede también crear un Stream a partir de un array utilizando el método Stream.of(T... values)
:
String[] array = {"a", "b", "c"};
Stream<String> stream = Stream.of(array);
Incluso, se puede crear un Stream de valores individuales:
Stream<String> stream = Stream.of("a", "b", "c");
También existen maneras de crear Streams infinitos. Por ejemplo, el método Stream.iterate()
crea un Stream infinito basado en una función generadora. A continuación se presenta un ejemplo de un Stream que genera números pares:
Stream<Integer> stream = Stream.iterate(0, n -> n + 2);
Otro método para crear un Stream infinito es Stream.generate()
, que toma un objeto Supplier
y genera un Stream infinito de elementos. Por ejemplo, el siguiente código crea un Stream infinito de números aleatorios:
Stream<Double> stream = Stream.generate(Math::random);
Es importante destacar que los Streams infinitos deben usarse con precaución, ya que operaciones como count()
, collect()
o forEach()
generarán un bucle infinito. Por este motivo, se debe utilizar el método limit()
para limitar la cantidad de elementos que se procesarán:
Stream<Integer> stream = Stream.iterate(0, n -> n + 2).limit(10);
El código anterior genera un Stream de los primeros 10 números pares.
Operaciones con Streams
Una vez creado un Stream, se pueden realizar varias operaciones sobre él. Las operaciones de Stream se clasifican en dos categorías: operaciones intermedias y operaciones finales.
Las operaciones intermedias, como filter()
, map()
, flatMap()
y sorted()
, transforman un Stream en otro Stream. Son "lazy", lo que significa que no se ejecutan hasta que se invoca una operación final. Además, las operaciones intermedias se pueden encadenar.
Las operaciones finales, como collect()
, forEach()
, reduce()
, count()
, min()
, max()
y los métodos de coincidencia, producen un resultado o un efecto secundario. Una vez que se invoca una operación final, el Stream se consume y ya no se puede utilizar más.
Aquí se muestran algunos ejemplos de operaciones con Streams.
Operaciones Intermedias
filter()
: Toma unPredicate
como argumento y devuelve un Stream que incluye solo los elementos que cumplen con el predicado.
Stream<String> stream = Stream.of("a", "b", "c", "d");
Stream<String> longWords = stream.filter(w -> w.length() > 1);
map()
: Toma unaFunction
como argumento y transforma los elementos del Stream aplicando la función a cada elemento.
Stream<String> stream = Stream.of("a", "b", "c", "d");
Stream<String> upperCaseWords = stream.map(String::toUpperCase);
flatMap()
: Se usa para aplanar una estructura de datos. Toma unaFunction
que devuelve un Stream para cada elemento y luego combina todos los Streams en uno solo.
List<String> words = Arrays.asList("Hello", "World");
Stream<String> letters = words.stream().flatMap(word -> Stream.of(word.split("")));
sorted()
: Produce un Stream que está ordenado de acuerdo con su orden natural o unComparator
proporcionado.
Stream<String> stream = Stream.of("c", "a", "b", "d");
Stream<String> sortedStream = stream.sorted();
distinct()
: Devuelve un Stream con elementos únicos (elimina duplicados).
Stream<String> stream = Stream.of("a", "b", "c", "a", "b");
Stream<String> distinctStream = stream.distinct();
Operaciones Finales
forEach()
: Toma unConsumer
y aplica la operación a cada elemento del Stream.
Stream<String> stream = Stream.of("a", "b", "c", "d");
stream.forEach(System.out::println);
collect()
: Es una operación muy versátil que transforma los elementos del Stream en una estructura de datos diferente.
Stream<String> stream = Stream.of("a", "b", "c", "d");
List<String> list = stream.collect(Collectors.toList());
reduce()
: Reduce los elementos del Stream a un solo valor. Toma un valor inicial y una función binaria y produce un resultado opcional.
Stream<Integer> stream = Stream.of(1, 2, 3, 4, 5);
Optional<Integer> sum = stream.reduce(Integer::sum);
count()
: Devuelve la cantidad de elementos en el Stream.
Stream<String> stream = Stream.of("a", "b", "c", "d");
long count = stream.count();
min()
ymax()
: Devuelven el elemento mínimo y máximo del Stream, respectivamente, según unComparator
proporcionado.
Stream<String> stream = Stream.of("a", "b", "c", "d");
Optional<String> min = stream.min(Comparator.naturalOrder());
- Métodos de coincidencia:
anyMatch()
,allMatch()
ynoneMatch()
: Estos métodos toman unPredicate
y devuelven un booleano.anyMatch()
devuelve verdadero si cualquier elemento del Stream coincide con el predicado.allMatch()
devuelve verdadero si todos los elementos del Stream coinciden con el predicado.noneMatch()
devuelve verdadero si ningún elemento del Stream coincide con el predicado.
Stream<String> stream = Stream.of("a", "b", "c", "d");
boolean anyMatch = stream.anyMatch("a"::equals);
API Optional
Finalmente, es importante mencionar la API Optional
que fue introducida en Java 8 junto con los Streams. Optional
es una envoltura que puede contener o no un valor. Se utiliza para representar valores opcionales que pueden ser ausentes. Muchas operaciones de Stream, como min()
, max()
y reduce()
, devuelven un Optional
.
Por ejemplo, la operación max()
en el siguiente código devuelve un Optional
:
Stream<String> stream = Stream.of("a", "b", "c", "d");
Optional<String> max = stream.max(Comparator.naturalOrder());
Para obtener el valor de un Optional
, se puede utilizar el método get()
. Sin embargo, este método lanza una excepción si el Optional
está vacío. Por lo tanto, es recomendable utilizar el método isPresent()
para comprobar si el Optional
contiene un valor antes de llamar a get()
:
if (max.isPresent()) {
System.out.println(max.get());
}
Además, se pueden encadenar métodos como orElse()
, orElseGet()
, y orElseThrow()
para proporcionar alternativas o lanzar excepciones cuando el Optional
está vacío.
En conclusión, los Streams en Java SE son una herramienta poderosa para el procesamiento de datos y la programación funcional. Permiten al programador escribir código más declarativo y legible, lo cual puede ayudar a reducir los errores y mejorar la productividad. Aunque se necesita un tiempo para familiarizarse con los conceptos de los Streams y la programación funcional, el esfuerzo vale la pena por los beneficios que aportan.
Ejercicios de esta lección Creación de Streams
Evalúa tus conocimientos de esta lección Creación de Streams con nuestros retos de programación de tipo Test, Puzzle, Código y Proyecto con VSCode, guiados por IA.
Clases abstractas
Streams: reduce()
Streams: flatMap()
Llamada y sobrecarga de funciones
Métodos referenciados
Métodos de la clase String
Representación de Fecha
Operadores lógicos
Tipos de datos
Estructuras de iteración
Streams: forEach()
Objetos
Funciones lambda
Uso de Scanner
CRUD en Java de modelo Customer sobre un ArrayList
Tipos de variables
Streams: collect()
Operadores aritméticos
Interfaz funcional Consumer
API java.nio 2
API Optional
Interfaz funcional Function
Encapsulación
Interfaces
Uso de API Optional
Representación de Hora
Herencia básica
Clases y objetos
Interfaz funcional Supplier
HashMap
Sobrecarga de métodos
Polimorfismo de tiempo de ejecución
OOP en Java
Creación de Streams
Streams: min max
Métodos avanzados de la clase String
Polimorfismo de tiempo de compilación
Excepciones
Herencia avanzada
Estructuras de selección
Uso de interfaces
HashSet
Objeto Scanner
Streams: filter()
Operaciones de Streams
Interfaz funcional Predicate
Streams: sorted()
Configuración de entorno
CRUD en Java de modelo Customer sobre un HashMap
Uso de variables
Clases
Streams: distinct()
Streams: count()
ArrayList
Datos de referencia
Interfaces funcionales
Métodos básicos de la clase String
Instalación
Funciones
Estructuras de control
Herencia de clases
Streams: map()
Funciones y encapsulamiento
Streams: match
Gestión de errores y excepciones
Datos primitivos
Todas las lecciones de Java
Accede a todas las lecciones de Java y aprende con ejemplos prácticos de código y ejercicios de programación con IDE web sin instalar nada.
Introducción A Javascript
Sintaxis
Tipos De Datos
Sintaxis
Variables
Sintaxis
Operadores
Sintaxis
Estructuras De Control
Sintaxis
Funciones
Sintaxis
Funciones Cierre (Closure)
Sintaxis
Funciones Flecha
Programación Funcional
Filtrado Con Filter() Y Find()
Programación Funcional
Transformación Con Map()
Programación Funcional
Reducción Con Reduce()
Programación Funcional
Clases Y Objetos
Programación Orientada A Objetos
Excepciones
Programación Orientada A Objetos
Encapsulación
Programación Orientada A Objetos
Herencia
Programación Orientada A Objetos
Polimorfismo
Programación Orientada A Objetos
Array
Estructuras De Datos
Conjuntos Con Set
Estructuras De Datos
Mapas Con Map
Estructuras De Datos
Manipulación Dom
Dom
Selección De Elementos Dom
Dom
Modificación De Elementos Dom
Dom
Eventos Del Dom
Dom
Callbacks
Programación Asíncrona
Promises
Programación Asíncrona
Async / Await
Programación Asíncrona
Instalación De Java
Introducción Y Entorno
Configuración De Entorno Java
Introducción Y Entorno
Ecosistema Jakarta Ee De Java
Introducción Y Entorno
Tipos De Datos
Sintaxis
Variables
Sintaxis
Operadores
Sintaxis
Estructuras De Control
Sintaxis
Funciones
Sintaxis
Excepciones
Programación Orientada A Objetos
Clases Y Objetos
Programación Orientada A Objetos
Encapsulación
Programación Orientada A Objetos
Herencia
Programación Orientada A Objetos
Clases Abstractas
Programación Orientada A Objetos
Interfaces
Programación Orientada A Objetos
Sobrecarga De Métodos
Programación Orientada A Objetos
Polimorfismo
Programación Orientada A Objetos
La Clase Scanner
Programación Orientada A Objetos
Métodos De La Clase String
Programación Orientada A Objetos
Listas
Framework Collections
Conjuntos
Framework Collections
Mapas
Framework Collections
Funciones Lambda
Programación Funcional
Interfaz Funcional Consumer
Programación Funcional
Interfaz Funcional Predicate
Programación Funcional
Interfaz Funcional Supplier
Programación Funcional
Interfaz Funcional Function
Programación Funcional
Métodos Referenciados
Programación Funcional
Creación De Streams
Programación Funcional
Operaciones Intermedias Con Streams: Map()
Programación Funcional
Operaciones Intermedias Con Streams: Filter()
Programación Funcional
Operaciones Intermedias Con Streams: Distinct()
Programación Funcional
Operaciones Finales Con Streams: Collect()
Programación Funcional
Operaciones Finales Con Streams: Min Max
Programación Funcional
Operaciones Intermedias Con Streams: Flatmap()
Programación Funcional
Operaciones Intermedias Con Streams: Sorted()
Programación Funcional
Operaciones Finales Con Streams: Reduce()
Programación Funcional
Operaciones Finales Con Streams: Foreach()
Programación Funcional
Operaciones Finales Con Streams: Count()
Programación Funcional
Operaciones Finales Con Streams: Match
Programación Funcional
Api Optional
Programación Funcional
Api Java.nio 2
Entrada Y Salida (Io)
Api Java.time
Api Java.time
Certificados de superación de Java
Supera todos los ejercicios de programación del curso de Java y obtén certificados de superación para mejorar tu currículum y tu empleabilidad.
En esta lección
Objetivos de aprendizaje de esta lección
- Comprender qué es un Stream en Java y su relación con la programación funcional.
- Aprender a crear Streams a partir de diferentes estructuras de datos como listas, arrays o valores individuales.
- Conocer cómo se generan Streams infinitos y cómo limitarlos correctamente.
- Entender las operaciones intermedias en Streams como
filter()
,map()
,flatMap()
,sorted()
ydistinct()
. - Manejar las operaciones finales en Streams como
forEach()
,collect()
,reduce()
,count()
,min()
,max()
y los métodos de coincidencia. - Comprender el uso y funcionamiento de la API Optional para gestionar resultados potencialmente ausentes en operaciones de Streams.