Datos de prueba:
public class DatosEmpleado {
public static List<Empleado> obtenerEmpleados(){
List<Empleado> lista = new ArrayList<>();
lista.add(new Empleado(1001, "Ana García", 34, 6000.38));
lista.add(new Empleado(1002, "Carlos López", 28, 9876.12));
lista.add(new Empleado(1003, "María Rodríguez", 33, 3000.82));
lista.add(new Empleado(1004, "Pedro Martínez", 26, 7657.37));
lista.add(new Empleado(1005, "Laura Sánchez", 65, 5555.32));
lista.add(new Empleado(1006, "David Fernández", 42, 9500.43));
lista.add(new Empleado(1007, "Elena Pérez", 26, 4333.32));
lista.add(new Empleado(1008, "Javier Gómez", 35, 2500.32));
return lista;
}
}
Tres etapas principales
1. Creación del Stream
En Java 8, las interfaces de colección proporcionan dos métodos para generar streams:
- stream() - Crea un stream secuencial
- parallelStream() - Crea un stream paralelo
- Método estático stream() de Arrays
- Método of() de Stream
2. Operaciones intermedias del Stream
Múltiples operaciones intermedias pueden encadenarse para formar una pipeline.
2.1. Filtrado y segmentación
2.2. Transformación
2.3. Ordenación
3. Operaciones terminales del Stream
Las operaciones terminales producen resultados a partir de la pipeline. El resultado puede ser cualquier valor que no sea un stream, como List, Integer, o incluso void.
Una vez que se ejecuta una operación terminal, el stream no puede reutilizarse.
count()retorna el número total de elementosmax(Comparator c)retorna el valor máximomin(Comparator c)retorna el valor mínimoforEach(Consumer c)iteración interna (a diferencia de las colecciones que requieren iteración externa)
Reducción y recolección
reduce(T iden, BinaryOperator b)combina repetidamente los elementos del stream para producir un valor. Retorna Tcollect(Collector c)transforma el stream a otra forma. Recibe una implementación de Collectro para realizar operaciones de resumen
- Ejemplo uno
/**
* 1. Stream se enfoca en operaciones con datos, interactuando con la CPU
* Las colecciones se enfocan en almacenamiento de datos, interactuando con la memoria
*
* 2. Características principales:
* ① Stream no almacena elementos por sí mismo
* ② Stream no modifica el objeto fuente. En su lugar, retorna un nuevo Stream con el resultado
* ③ Las operaciones de Stream son de ejecución diferida. Se ejecutan solo cuando se necesita el resultado
*
* 3. Flujo de ejecución de Stream:
* ① Instanciación del Stream
* ② Serie de operaciones intermedias (filtrado, transformación, ...)
* ③ Operación terminal
*
* 4. Explicación:
* 4.1 Una cadena de operaciones intermedias procesa los datos de la fuente
* 4.2 Al ejecutar la operación terminal, se ejecuta la cadena de operaciones y se produce el resultado
*/
public class PruebaStreamAPI {
//Método 1: Creación mediante colección
@Test
public void prueba1(){
List<Empleado> empleados = DatosEmpleado.obtenerEmpleados();
// Stream secuencial
Stream<Empleado> stream = empleados.stream();
// Stream paralelo
Stream<Empleado> streamParalelo = empleados.parallelStream();
}
//Método 2: Creación mediante array
@Test
public void prueba2(){
int[] numeros = {1,2,3,4,5,6};
IntStream streamNumeros = Arrays.stream(numeros);
Empleado emp1 = new Empleado(1001,"Juan");
Empleado emp2 = new Empleado(1002,"María");
Empleado[] empleadosArray = {emp1, emp2};
Stream<Empleado> streamEmpleados = Arrays.stream(empleadosArray);
}
//Método 3: Creación mediante Stream.of()
@Test
public void prueba3(){
Stream<Integer> stream = Stream.of(10, 20, 30, 40, 50);
}
//Método 4: Creación de stream infinito
@Test
public void prueba4(){
// Iteración - primeros 10 números pares
Stream.iterate(0, n -> n + 2).limit(10).forEach(System.out::println);
// Generación - 10 números aleatorios
Stream.generate(Math::random).limit(10).forEach(System.out::println);
}
}
/**
* Prueba de operaciones intermedias del Stream
*/
public class PruebaStreamOperacionesIntermedias {
//1-Filtrado y segmentación
@Test
public void pruebaFiltrado(){
List<Empleado> empleados = DatosEmpleado.obtenerEmpleados();
// Filtrado por salario
empleados.stream()
.filter(emp -> emp.getSalario() > 7000)
.forEach(System.out::println);
System.out.println();
// Limitar resultados
empleados.stream().limit(3).forEach(System.out::println);
System.out.println();
// Saltar elementos
empleados.stream().skip(2).forEach(System.out::println);
System.out.println();
// Eliminar duplicados
empleados.add(new Empleado(1010,"Carlos Ruiz",40,8000));
empleados.add(new Empleado(1010,"Carlos Ruiz",40,8000));
empleados.stream().distinct().forEach(System.out::println);
}
//Transformación
@Test
public void pruebaTransformacion(){
List<String> textos = Arrays.asList("java", "stream", "api", "ejemplo");
// Transformar a mayúsculas
textos.stream()
.map(String::toUpperCase)
.forEach(System.out::println);
// Nombres de empleados con longitud mayor a 5
List<Empleado> empleados = DatosEmpleado.obtenerEmpleados();
empleados.stream()
.map(Empleado::getNombre)
.filter(nombre -> nombre.length() > 5)
.forEach(System.out::println);
System.out.println();
// Transformación plana
Stream<Character> caracteres = textos.stream()
.flatMap(this::convertirACaracteres);
caracteres.forEach(System.out::println);
}
// Convertir string a stream de caracteres
private Stream<Character> convertirACaracteres(String texto){
List<Character> listaCaracteres = new ArrayList<>();
for(char c : texto.toCharArray()){
listaCaracteres.add(c);
}
return listaCaracteres.stream();
}
//3-Ordenación
@Test
public void pruebaOrdenacion(){
// Ordenación natural
List<Integer> numeros = Arrays.asList(15, 8, 23, 4, 42, 11);
numeros.stream().sorted().forEach(System.out::println);
// Ordenación personalizada
List<Empleado> empleados = DatosEmpleado.obtenerEmpleados();
empleados.stream().sorted((e1, e2) -> {
int comparacionEdad = Integer.compare(e1.getEdad(), e2.getEdad());
if(comparacionEdad != 0){
return comparacionEdad;
} else {
return Double.compare(e1.getSalario(), e2.getSalario());
}
}).forEach(System.out::println);
}
}
/**
* Prueba de operaciones terminales del Stream
*/
public class PruebaStreamOperacionesTerminales {
//1-Coincidencia y búsqueda
@Test
public void pruebaCoincidencia(){
List<Empleado> empleados = DatosEmpleado.obtenerEmpleados();
// Verificar si todos los empleados son mayores de 18
boolean todosMayores = empleados.stream()
.allMatch(emp -> emp.getEdad() > 18);
System.out.println("Todos mayores de 18: " + todosMayores);
// Verificar si algún empleado gana más de 9000
boolean algunoAltoSalario = empleados.stream()
.anyMatch(emp -> emp.getSalario() > 9000);
System.out.println("Algún salario alto: " + algunoAltoSalario);
// Primer empleado
Optional<Empleado> primerEmpleado = empleados.stream().findFirst();
System.out.println("Primer empleado: " + primerEmpleado);
}
@Test
public void pruebaBusqueda(){
List<Empleado> empleados = DatosEmpleado.obtenerEmpleados();
// Contar empleados con salario mayor a 5000
long cantidad = empleados.stream()
.filter(emp -> emp.getSalario() > 5000)
.count();
System.out.println("Empleados con salario > 5000: " + cantidad);
// Salario máximo
Optional<Double> salarioMaximo = empleados.stream()
.map(Empleado::getSalario)
.max(Double::compare);
System.out.println("Salario máximo: " + salarioMaximo);
// Empleado con salario mínimo
Optional<Empleado> empleadoMinSalario = empleados.stream()
.min((e1, e2) ->
Double.compare(e1.getSalario(), e2.getSalario()));
System.out.println("Empleado mínimo salario: " + empleadoMinSalario);
}
//2-Reducción
@Test
public void pruebaReduccion(){
// Suma de números
List<Integer> numeros = Arrays.asList(5, 10, 15, 20, 25);
Integer suma = numeros.stream().reduce(0, Integer::sum);
System.out.println("Suma: " + suma);
// Suma total de salarios
List<Empleado> empleados = DatosEmpleado.obtenerEmpleados();
Optional<Double> totalSalarios = empleados.stream()
.map(Empleado::getSalario)
.reduce((s1, s2) -> s1 + s2);
System.out.println("Total salarios: " + totalSalarios.get());
}
//3-Recolección
@Test
public void pruebaRecoleccion(){
List<Empleado> empleados = DatosEmpleado.obtenerEmpleados();
// Empleados con salario > 6000 como Lista
List<Empleado> empleadosAltosSalarios = empleados.stream()
.filter(emp -> emp.getSalario() > 6000)
.collect(Collectors.toList());
empleadosAltosSalarios.forEach(System.out::println);
System.out.println();
// Como Set
Set<Empleado> conjuntoEmpleados = empleados.stream()
.filter(emp -> emp.getSalario() > 6000)
.collect(Collectors.toSet());
conjuntoEmpleados.forEach(System.out::println);
}
}