🔹 ¿Para qué se usa stream()?
El objetivo de stream() es:
👉 procesar colecciones de datos de forma declarativa (más expresiva y menos
código)
En lugar de decir cómo iterar (for, índices, acumuladores), dices qué quieres hacer.
Ejemplo clásico sin streams:
double total = 0;
for (Venta v : ventas) {
total += [Link]();
}
Con streams:
double total = [Link]()
.mapToDouble(Venta::calcularTotal)
.sum();
👉 Se busca:
código más limpio
menos errores
posibilidad de paralelismo
operaciones encadenadas (pipeline)
🔹 Ahora: ejemplo didáctico completo
Supongamos esto:
Libro libro1 = new Libro("Java", 50.0, 10);
Libro libro2 = new Libro("Python", 30.0, 10);
Cliente c1 = new Cliente("Juan");
Cliente c2 = new Cliente("Ana");
List<Venta> ventas = [Link](
new Venta(1, 2, c1, libro1), // 2 * 50 = 100
new Venta(2, 1, c2, libro2), // 1 * 30 = 30
new Venta(3, 3, c1, libro2) // 3 * 30 = 90
);
Entonces tienes esto en memoria:
Venta cantidad precio libro total
v1 2 50 100
v2 1 30 30
v3 3 30 90
🔹 Ahora evaluemos esta línea:
[Link]().mapToDouble(Venta::calcularTotal).sum();
🧠 PASO A PASO (muy detallado)
1. [Link]()
👉 Convierte la lista en un flujo de datos:
[Venta1, Venta2, Venta3]
Pero no ejecuta nada todavía (esto es clave).
Es como decir:
"Voy a empezar a procesar estos elementos"
2. .mapToDouble(Venta::calcularTotal)
Aquí ocurre lo importante:
👉 A cada Venta se le aplica:
venta -> [Link]()
Entonces conceptualmente pasa esto:
Venta1 → 100
Venta2 → 30
Venta3 → 90
Ahora el stream ya no es de Venta, sino de double:
[100.0, 30.0, 90.0]
Esto es un DoubleStream.
3. .sum()
👉 Recorre los valores y los suma:
100 + 30 + 90 = 220
Resultado final:
220.0
🔹 Visualización mental tipo "pipeline"
Imagina una tubería:
[Venta1, Venta2, Venta3]
│
▼
calcularTotal()
│
▼
[100, 30, 90]
│
▼
sum()
│
▼
220
🔹 Algo MUY importante (punto clave)
Los streams son perezosos (lazy).
👉 Eso significa que:
mapToDouble() no se ejecuta inmediatamente
TODO se ejecuta recién cuando llamas a .sum()
Internamente, Java hace algo más parecido a esto:
double total = 0;
for (Venta v : ventas) {
total += [Link]();
}
Pero optimizado.
🔹 ¿Qué recibe cada parte?
stream()
recibe: una colección (List<Venta>)
devuelve: Stream<Venta>
mapToDouble()
recibe: función Venta -> double
devuelve: DoubleStream
sum()
recibe: nada (es terminal)
devuelve: double
🔹 ¿Por qué usar esto y no un for?
Porque puedes hacer cosas mucho más complejas fácilmente:
[Link]()
.filter(v -> [Link]() > 1)
.mapToDouble(Venta::calcularTotal)
.average();
👉 Eso con un for ya se vuelve más largo y propenso a errores.
🔹 Resumen claro
stream() → convierte la lista en un flujo
mapToDouble() → transforma cada elemento en un double
sum() → suma los valores
👉 Es una forma elegante de hacer lo mismo que un for, pero más declarativa.
Si quieres, en el siguiente paso te puedo mostrar:
cómo Java ejecuta esto internamente (más bajo nivel)
o ejemplos con filter, map, reduce que son el verdadero poder de streams