|
| 1 | +package com.platzi.functional._16_listeners; |
| 2 | + |
| 3 | +import com.platzi.functional.util.Utils; |
| 4 | + |
| 5 | +import java.util.List; |
| 6 | +import java.util.concurrent.atomic.AtomicInteger; |
| 7 | +import java.util.stream.Stream; |
| 8 | + |
| 9 | +public class StreamListeners { |
| 10 | + static void listeners() { |
| 11 | + /* |
| 12 | + Mencionamos que los Streams son "auto iterables" |
| 13 | + Entonces… como podemos obtener los datos para procesarlos? |
| 14 | +
|
| 15 | + Es facil, la clase Stream tiene un API funcional que nos permite pasar Suppliers, Consumers, |
| 16 | + Predicates, etc. Lambdas a final de cuentas. |
| 17 | + */ |
| 18 | + Stream<String> coursesStream = Stream.of("Java", "Functional"); |
| 19 | + coursesStream.forEach(course -> System.out.println("Curso de platzi sobre: " + course)); |
| 20 | + |
| 21 | + /* |
| 22 | + A estas lambdas o funciones que agregamos para procesar los streams, se les conoce como listeners. |
| 23 | +
|
| 24 | + Aunque este nombre/definicion depende del autor, tiene mucho sentido llamarles asi, |
| 25 | + pues el Stream se empezara a iterar una vez que encuentre el set de datos y las operaciones |
| 26 | + a aplicar e ira invocando a cada una de estas operaciones con los valores correspondientes. |
| 27 | + */ |
| 28 | + |
| 29 | + /* |
| 30 | + Hay diferentes tipos de operaciones que aceptan diferentes tipos de listeners, por ejemplo, |
| 31 | + el filtrado de datos: |
| 32 | + */ |
| 33 | + AtomicInteger x = new AtomicInteger(); |
| 34 | + Stream<Integer> countingStream = Stream.generate(() -> x.getAndIncrement()); |
| 35 | + |
| 36 | + //Filtramos los datos para tener solo los numeros pares producidos por el stream |
| 37 | + countingStream.filter(i -> i % 2 == 0); |
| 38 | + |
| 39 | + //O elevamos cada numero al cuadrado… |
| 40 | + countingStream.map(i -> i * i); |
| 41 | + |
| 42 | +// |
| 43 | +// |
| 44 | +// |
| 45 | +// |
| 46 | + |
| 47 | + /* |
| 48 | + Una situacion que se presenta en muchas ocasiones es tener un Stream<List<String>> donde |
| 49 | + tenemos un Stream que emite colecciones. |
| 50 | + Si intentamos operar sobre estre Stream no podremos acceder a los Strings de cada lista, |
| 51 | + solo a las listas como tal… operar de vuelta la lista no es una opcion si estamos haciendo |
| 52 | + cosas en paralelo. |
| 53 | + */ |
| 54 | + Stream<List<String>> coursesModules = Stream.of(/*Obentemos los cursos de una DB*/); |
| 55 | + //Nos devuelve un Stream de List<String> donde las listas tienen literalmente el elemento "Java" |
| 56 | + //Tal vez nuestra busqueda era sobre cursos que contuvieran la palabra Java como parte del nombre… |
| 57 | + coursesModules.filter(s -> s.contains("Java")); |
| 58 | + |
| 59 | + /* |
| 60 | + Para poder operar este tipo de streams, usaremos una operacion llamada flatMap |
| 61 | +
|
| 62 | + flatMap toma un Stream<Collecion<T>> y nos devuelve un Stream<T>. |
| 63 | +
|
| 64 | + Es decir, flatMap se encarga de combianr todos los elementos de las colecciones de los streams |
| 65 | + en un solo Stream. Para hacer esto, debemos proveer una lambda que emita un stream como resultado |
| 66 | +
|
| 67 | + Si nuestro Stream inicial tenia: |
| 68 | + Stream{ List{ "Node.js", "JavaScript"}, List{"Android", "Kotlin"}, List{"JavaSE 8", "Java FP"}} |
| 69 | +
|
| 70 | + Aplicar flatMap devuelve: |
| 71 | + Stream{ "Node.js", "JavaScript", "Android", "Kotlin", "JavaSE 8", "Java FP" } |
| 72 | + */ |
| 73 | + List<String> nodeCourses = Utils.getListOf("Node.js", "Express.js", "Eventloop"); |
| 74 | + List<String> javaCourses = Utils.getListOf("Spring", "Maven", "Gradle", "Funtional"); |
| 75 | + |
| 76 | + Stream<List<String>> courses = Stream.of(nodeCourses, javaCourses); |
| 77 | + |
| 78 | + //Sin flatMap |
| 79 | + long jsCourses = courses.filter(course -> course.contains("js")).count(); |
| 80 | + System.out.println(jsCourses); // 0 |
| 81 | + |
| 82 | + jsCourses = courses.flatMap(list -> list.stream()) //Tambien Collection::stream es valido |
| 83 | + .filter(course -> course.contains("js")) |
| 84 | + .count(); // 2 (Node.js, Express.js) |
| 85 | + |
| 86 | +// |
| 87 | +// |
| 88 | +// |
| 89 | +// |
| 90 | +// |
| 91 | + /* |
| 92 | + Hablamos un poco sobre como crear streams desde una funcion y que estos streams pueden |
| 93 | + emitir datos invocando a esta funcion. |
| 94 | +
|
| 95 | + Sin embargo… que los detiene? Estos streams son infinitos, para detenerlos podemos utilizar `limit` |
| 96 | + */ |
| 97 | + Stream<Integer> firstTen = Stream.iterate(0, i -> i + 1); |
| 98 | + firstTen.limit(10) |
| 99 | + .forEach(System.out::println); |
| 100 | + |
| 101 | + |
| 102 | + |
| 103 | + |
| 104 | + /* |
| 105 | + Tambien es posible que usemos objetos en lugar de lambdas. Recordemos que al final las lambdas |
| 106 | + son funciones y los metodos son funciones. Podemos usar objetos siempre que sus |
| 107 | + metodos cumplan con la necesidad de tener los parametros correctos y devolver el tipo correcto. |
| 108 | + */ |
| 109 | + NumericOperator numericOperator = new NumericOperator(); |
| 110 | + Stream<Integer> numbers = Stream.iterate(0, numericOperator::operate); |
| 111 | + firstTen.limit(10) |
| 112 | + .forEach(System.out::println); |
| 113 | + } |
| 114 | +// |
| 115 | +// |
| 116 | +// |
| 117 | +// |
| 118 | + static class NumericOperator { |
| 119 | + public int operate(int x) { |
| 120 | + return x + 3; |
| 121 | + } |
| 122 | + } |
| 123 | +} |
0 commit comments