Skip to content

Commit 25ee996

Browse files
committed
Explicacion de operaciones y collectors
- Also: corregido 'devuelve' -> 'retorna' en los comentarios
1 parent 2ec4b48 commit 25ee996

7 files changed

Lines changed: 175 additions & 9 deletions

File tree

modules/src/main/java/com/platzi/functional/_04_functional/_01_FunctionDemo.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@ public RESULT apply(TYPE t) {
3333

3434

3535
/**
36-
* Veamos un ejemplo simple… una funcion que nos devuelve si un numero es par
36+
* Veamos un ejemplo simple… una funcion que nos retorna si un numero es par
3737
*/
3838
private static void functionExample() {
3939
Function<Integer, Boolean> isEven = new Function<Integer, Boolean>() {

modules/src/main/java/com/platzi/functional/_04_functional/_04_OperatorsAndBiFunctions.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ public class _04_OperatorsAndBiFunctions {
1313
private static void unaries() {
1414
//Aunque esta funcion luce muy parecida a una que ya usamos previamente,
1515
//el tenerla como UnaryOperator nos deja en claro que es una operacion que
16-
//trabaja sobre un tipo y nos devuelve el mismo tipo.
16+
//trabaja sobre un tipo y nos retorna el mismo tipo.
1717
UnaryOperator<Integer> square = x -> x * x;
1818

1919
UnaryOperator<String> quote = s -> "\"" + s + "\"";

modules/src/main/java/com/platzi/functional/_06_reference_operator/_01_Operator.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -138,7 +138,7 @@ private void weirdStuff() {
138138
//con la definicion de la funcion que necesitamos:
139139

140140
/*
141-
La clase tiene definido este metodo que recibe un string y devuelve un int.
141+
La clase tiene definido este metodo que recibe un string y retorna un int.
142142
143143
144144
class HelperOperator {
@@ -147,7 +147,7 @@ public int sayNameAge(String s){…}
147147
}
148148
149149
150-
La funcion que tenemos que pasar, justamente, recibe un string y devuelve un int…
150+
La funcion que tenemos que pasar, justamente, recibe un string y retorna un int…
151151
152152
giveMeAFunction(Function<String, Integer> function)
153153

modules/src/main/java/com/platzi/functional/_12_currying/Currying.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
public class Currying {
66
/**
77
* Empecemos con algo que ya conocemos: una FunctionalInterface que toma 3 tipos de datos
8-
* F, S, T y devuelve un tipo de dato R cuando se manda a llamar su metodo apply.
8+
* F, S, T y retorna un tipo de dato R cuando se manda a llamar su metodo apply.
99
* <p>
1010
* Hasta que no deberia haber nada nuevo.
1111
*/

modules/src/main/java/com/platzi/functional/_14_optionals/Optionals.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -182,7 +182,7 @@ static Optional<String> conOptional(List<String> names) {
182182
* Funcion usando ambos casos:
183183
*/
184184
static void outside() {
185-
//Invocando a un metodo que no sabemos que devuelve:
185+
//Invocando a un metodo que no sabemos que retorna:
186186
String directResult = antesDeOptional(null);
187187
if (directResult != null) {
188188
directResult = directResult.replace("Sierisimo", "Sinuhe");

modules/src/main/java/com/platzi/functional/_16_listeners/StreamListeners.java

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -52,22 +52,22 @@ static void listeners() {
5252
cosas en paralelo.
5353
*/
5454
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"
55+
//Nos retorna un Stream de List<String> donde las listas tienen literalmente el elemento "Java"
5656
//Tal vez nuestra busqueda era sobre cursos que contuvieran la palabra Java como parte del nombre…
5757
coursesModules.filter(s -> s.contains("Java"));
5858

5959
/*
6060
Para poder operar este tipo de streams, usaremos una operacion llamada flatMap
6161
62-
flatMap toma un Stream<Collecion<T>> y nos devuelve un Stream<T>.
62+
flatMap toma un Stream<Collecion<T>> y nos retorna un Stream<T>.
6363
6464
Es decir, flatMap se encarga de combianr todos los elementos de las colecciones de los streams
6565
en un solo Stream. Para hacer esto, debemos proveer una lambda que emita un stream como resultado
6666
6767
Si nuestro Stream inicial tenia:
6868
Stream{ List{ "Node.js", "JavaScript"}, List{"Android", "Kotlin"}, List{"JavaSE 8", "Java FP"}}
6969
70-
Aplicar flatMap devuelve:
70+
Aplicar flatMap retorna:
7171
Stream{ "Node.js", "JavaScript", "Android", "Kotlin", "JavaSE 8", "Java FP" }
7272
*/
7373
List<String> nodeCourses = Utils.getListOf("Node.js", "Express.js", "Eventloop");
Lines changed: 166 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,166 @@
1+
package com.platzi.functional._17_operators_collectors;
2+
3+
import com.platzi.functional.util.Utils;
4+
5+
import java.util.Collection;
6+
import java.util.List;
7+
import java.util.stream.Collectors;
8+
import java.util.stream.Stream;
9+
10+
public class Operators {
11+
static void operadores() {
12+
/*
13+
Hasta ahora hemos usado lambdas indiscriminadamente en nuestros streams sin revisar o validar
14+
el estado del stream. Es decir, si ejecutas algunos ejemplos anteriores puede que te encuentres con
15+
algunas excepciones no explicadas. Este es el tema donde explicaremos que diferencia hay entre usar
16+
17+
forEach vs map por ejemplo.
18+
*/
19+
20+
/*
21+
En nuestros streams, generalmente nos encontramos con elementos y realizamos operaciones sobre ellos.
22+
*/
23+
Stream<Integer> numbers = Utils.getListOf(1, 2, 3, 4).stream();
24+
numbers.map(i -> i * 2);
25+
26+
/*
27+
Sin embargo, ciertas operaciones nos retornan un resultado, por ejemplo, map genera un nuevo
28+
Stream<V> partiendo de un Stream<T>. Es decir, cada que realizamos una operacion `map` en un stream
29+
lo que hace en realidad es generar un nuevo Stream, donde a cada elemento se le ira aplicando
30+
la operacion que nosotros definimos.
31+
32+
Esto puede ser representado:
33+
*/
34+
Stream<Integer> numbersV2 = Utils.getListOf(1, 2, 3, 4).stream();
35+
Stream<Integer> numbresBy2 = numbersV2.map(i -> i * 2);
36+
37+
/*
38+
Mas importante aun es entender que una vez aplicado un operador sobre un stream este stream no puede ser
39+
usado de nuevo:
40+
*/
41+
Stream<Integer> squares = numbersV2.map(i -> i * i); //Genera un IllegalStateException.
42+
//Lo cual representa una pequeña limitante sobre el uso de streams.
43+
44+
/*
45+
Hay metodos que modifican los datos de nuestro stream y metodos que nos dejan obtener un resultado de
46+
la iteracion de los elementos del stream. En ambos casos se les conoce como Operations
47+
48+
Es importante identificar que muchos de estos retornan un nuevo Stream. Tras realizar una operacion
49+
sobre un stream, el dato que existe en el stream puede cambiar, aqui un ejemplo:
50+
*/
51+
Stream<String> courses = Stream.of(
52+
"Java:Introductorio",
53+
"Python:Introductorio",
54+
"Machine Learning:Avanzado",
55+
"JavaScript:Introductorio",
56+
"Node.js:Intermedio",
57+
"Android:Intermedio",
58+
"iOS:Intermedio"
59+
);
60+
61+
Stream<String> introductoryCourses = courses.filter(course -> course.contains("Introductorio"));
62+
63+
Stream<String[]> partsNames = introductoryCourses.map(course -> course.split(":"));
64+
65+
Stream<String[]> partsWithData = partsNames.filter(parts -> parts.length > 1);
66+
67+
Stream<String> justNamesStream = partsWithData.map(courseData -> courseData[0]);
68+
69+
Stream<String> justActualNamesPresent = justNamesStream.filter(name -> !name.isEmpty());
70+
71+
/*
72+
O en una version con chaining:
73+
74+
Stream<String> justNamesStream = courses.filter(c -> c.contains("Introductorio"))
75+
.map(c -> c.split(":"))
76+
.filter(parts -> parts.length > 1)
77+
.map(courseData -> courseData[0])
78+
.map(c -> c[0])
79+
.filter(name -> !name.isEmpty());
80+
*/
81+
82+
/*
83+
Existen operaciones que nos permite obtener un resultado final despues de operar sobre los elementos de un stream.
84+
85+
Cuando obtenemos un resultado final de la iteracion de un stream, se dice que se invoco una Operacion Final.
86+
87+
Es importante entender que aunque tengamos multiples operaciones sobre un Stream, el Stream no sera iterado
88+
hasta no agregar una operacion final. Esto es benefico pues podemos ir pasando el Stream por diferentes metodos/funciones
89+
hasta que sea necesario obtener el valor resultante.
90+
*/
91+
Stream<List<String>> coursesStream = getCourses();
92+
Stream<String> courseDataStream = flatMapCourses(coursesStream);
93+
Stream<String[]> partsStream = splitInformation(courseDataStream);
94+
Stream<String[]> filteredPartsStream = filterAdvanceCourses(partsStream);
95+
Stream<String> advanceCourseNamesStream = getNamesStream(filteredPartsStream);
96+
97+
/*
98+
hasta este punto, no se ha procesado ningun stream a pesar de las llamadas a metodos.
99+
Esto es porque no se ha agregado una operacion final que desencadene la iteracion en el
100+
ningun stream.
101+
102+
Agregar una operacion final es tan sencillo como agregar una operacion no final:
103+
*/
104+
//long totalAdvanceCourses = advanceCourseNamesStream.count();
105+
106+
/*
107+
Es hasta este punto que los datos se empiezan a iterar para obtener un resultado.
108+
Sabemos que `count()` es una operacion final porque no retorna un Stream, retorna un
109+
resultado de aplicar la operacion correspondiente.
110+
111+
En muchas ocasiones lo mas comun es encontrarte con una operacion de recoleccion de datos
112+
utilizando una de las implementaciones de Collector.
113+
114+
Esta es la manera ideal de convertir un Stream a una coleccion (Set, Map, List, Collection)
115+
o convertir todos los datos de un Stream a un tipo en concreto (por ejemplo, concatenar todos los elementos)
116+
*/
117+
List<String> advanceCourseNamesList = advanceCourseNamesStream.collect(Collectors.toList());
118+
119+
//
120+
//
121+
//
122+
//
123+
124+
/*
125+
El ejemplo anterior representa algo sucediendo entre multiples partes de un proyecto,
126+
una que procese el dato de una peticion web, otro que lo almacene en una base de datos
127+
otro que haga conversion de datos… etc.
128+
*/
129+
}
130+
131+
//
132+
//
133+
//
134+
//
135+
//
136+
//
137+
//
138+
//
139+
//
140+
//
141+
//
142+
//
143+
static Stream<List<String>> getCourses() {
144+
List<String> nodeCourses = Utils.getListOf("Node.js:Intermedio", "Express.js:Intermedio", "Eventloop:Avanzado");
145+
List<String> javaCourses = Utils.getListOf("Spring:Introductorio", "Maven:Intermedio", "Gradle:Avanzado", "Funtional:Introductorio");
146+
147+
return Stream.of(nodeCourses, javaCourses);
148+
}
149+
150+
static Stream<String> flatMapCourses(Stream<List<String>> courses) {
151+
return courses.flatMap(Collection::stream);
152+
}
153+
154+
static Stream<String[]> splitInformation(Stream<String> coursesData) {
155+
return coursesData.map(courseData -> courseData.split(":"));
156+
}
157+
158+
static Stream<String[]> filterAdvanceCourses(Stream<String[]> courses) {
159+
return courses.filter(data -> data.length > 1)
160+
.filter(data -> data[1] == "Avanzado");
161+
}
162+
163+
static Stream<String> getNamesStream(Stream<String[]> coursesData) {
164+
return coursesData.map(courseData -> courseData[0]);
165+
}
166+
}

0 commit comments

Comments
 (0)