ProgramaciónDesarrollador Java

Explica qué es Java Stream API, cómo usarlo correctamente para operaciones de procesamiento de colecciones y qué matices se deben tener en cuenta al trabajar con flujos de datos.

Supere entrevistas con el asistente de IA Hintsage

Respuesta.

Historia de la pregunta:

Stream API se agregó en Java 8 para facilitar la programación funcional y el procesamiento paralelo de colecciones. Proporciona una manera conveniente de describir cadenas de operaciones sobre datos a través de expresiones lambda.

Problema:

Sin Stream API, era necesario escribir un código imperativo engorroso para filtrar, ordenar y agregar colecciones. Potencial de errores, complejidad de mantenimiento, ineficiencia al intentar agregar paralelismo manualmente.

Solución:

Stream API permite construir un pipeline de operaciones intermedias (intermediate) y terminales (terminal). Los flujos son perezosos, trabajan con datos de forma secuencial o paralela, el código se vuelve más compacto y expresivo.

Ejemplo de procesamiento de una colección:

List<String> names = Arrays.asList("Ana", "Juan", "Pedro", "Eva"); names.stream() .filter(s -> s.length() > 3) .map(String::toUpperCase) .sorted() .forEach(System.out::println);

Características clave:

  • Los flujos son perezosos: los cálculos solo se realizan en la operación terminal.
  • Después de la operación terminal, el flujo se considera cerrado.
  • Se puede pasar al procesamiento paralelo (parallelStream()), pero se deben tener en cuenta la seguridad de los hilos (thread-safety) de las colecciones y funciones.

Preguntas engañosas.

¿Se puede reutilizar el mismo Stream después de cerrarlo?

No, intentar reutilizar un Stream cerrado lanza IllegalStateException. Un flujo es de un solo uso.

¿Afecta la modificación de la colección original después de crear el Stream?

Sí, si la colección se modifica después de crear el Stream, pero antes de la operación terminal, pueden ocurrir ConcurrentModificationException.

¿Se pueden usar variables externas mutables dentro de las operaciones de Stream?

No se recomienda, ya que en un Stream paralelo puede llevar a errores inesperados. Es mejor evitar efectos secundarios mutables en el pipeline de Stream.

Errores típicos y anti-patrón

  • Uso de variables externas mutables dentro de lambda/stream.
  • Esperar un efecto inmediato de las operaciones intermedias (sin una operación terminal, no sucede nada).
  • Aplicar .parallelStream() a colecciones que no son seguras para hilos.

Ejemplo de la vida real

Caso negativo

Un programador llama a través de Stream a un método que cambia una lista externa: esto funciona en la ejecución secuencial, pero en paralelo puede desestructurar la estructura de datos.

Ventajas:

  • Código compacto.

Desventajas:

  • Pueden ocurrir condiciones de carrera, excepciones.
  • Violación de la seguridad de hilos.

Caso positivo

Todo el pipeline se construye de manera limpia: las operaciones no tienen efectos secundarios, solo se utilizan colecciones inmutables, el resultado final se recopila a través de un collector.

Ventajas:

  • Código seguro, legible y eficiente.
  • Fácil transición a flujos paralelos.

Desventajas:

  • Requiere acostumbrarse al estilo funcional.