Este paradigma me costó mucho al inicio, pero logre comprenderlo y a poder usarlo al menos en los retos del curso
Espero que les sirva 😃
Esta basado en funciones
Funciones es distinto a método
La función es un objeto que tiene ciertas cosas que la asemejan a un método
La diferencia es que es un objeto creado por la clase java.lang.function
Se usan funciones para almacenar datos, como si fueran variables
Función de orden mayor
Su resultado es una función
o se usa una funcion como parametro
Función pura
No depende de cosas externas
No genera efectos secundarios(no algo visible)
Una función pura no puede llamar a una impura
Función lambda (‘y’ al revés)
Función anónima; es decir no tiene nombre
Para usarla una sola vez o en un solo lugar
Es muy simple (una linea mayormente)
Datos inmutables
No se alter
Facilita el uso de funciones puras y threads
Seguridad en los datos
Funciones
Una función simple(Function) se puede definir de este modo
returnData functionName(param){
toDo;
}
es lo mismo que:
Function<paramType, returnData> functionName = paramVar -> {to do};
Las llaves se recomiendan solo si se ocupa más de una línea.
Se invoca con functionName.try();
Predicate
recibe un tipo de dato y devuelve un boolean
Predicate<dataType> predicateName = param -> toDo;
Se invoca con predicateName.test;
Consumer
Recibe un solo dato, normalmente un objeto y no devuelve nada
Consumer<consumedData> consumerName = paramVar -> {toDO};
Se invoca con consumerName.accept();
Supplier
NO recibe nada, devuelve un dato, puede ser un objeto
Supplier<generatedData> suppliername = () -> {toDO};
Se invoca con supplierName.get();
Operators
El parámetro (o los) son del mismo tipo
UnaryOperator- un solo parametro
BinaryOperator- dos (no estoy seguro si pueden ser más)
Operator<dataType> operatorName = param(s) -> {toDO};
Se invoca con operatorName.apply();
BiFunction
Similar a Operators pero los datos no deben ser del mismo tipo
BiFunction<paramType1, paramType2, returnDataType> BiFunctionName = params -> {toDo};
Crear un propio tipo de función
Esto se hace definiendo un interfaz SAM
single abstract method que tiene un solo método abstracto
y se utiliza @FuntionalInterface justo antes de iniciar la interfaz
esto se hace de la siguiente forma
@FuntionalInterface
interface nombre<instancias de objetos>{
(objeto que se retorna) methodName(params);
}
Se pueden hacer los métodos que deseemos
Al usar default se puede hacer un body en
vez de solo instanciar los
Cuando instanciamos una función el valor que le demos de
retorno será el que tome el primer método y debe corresponder al tipo
de dato
Referenciar
Esto se usa en caso de utilizar un método como si fuera
una función para esto se usan los dos dos puntos ::
esto se usa en vez del punto ejemplo
System.out::println
El primero no es :: porque no hace referencia directa al método
Dependiendo del valor que regresa y los parámetros que recibe puede ser
utilizado como cualquiera de las funciones
Por ejemplo System.out.println se puede usar como un consumidor porque recibe un parámetro
y no devuelve nada al igual que el consumer
Chaining
Esto es llamar un método a partir de otro por ejemplo
objeto.metodo().metodo2().metodo3().metodo();
Para lograr esto todos los métodos (el último no necesariamente
devuelve el mismo objeto en vez de ser un void
y al devolverlo podemos usarlo para llamar otro metodo del mismo
objeto
Composición
para componer funciones se usa compose y andthen
función.compose(lambda)
se ejecuta la lambda
funcion.andthen(lamba)
primero la lambda
Optional
Almacena algún tipo de dato dentro de este objeto lo que nos ayuda
cuando el objeto no existe o es nulo
Streams
Los streams son una estructura de datos que sirve más con la programación funcional debido
a que fueron creadas después por lo que podemos aplicar funciones
Solo se puede consumir un a vez
SU uso principal es simplificar operaciones como
filtrado mapeo y conversiones
Paralelismo
Al ejecutar en java para hacer el proceso más rápido el proceso se
divide en los núcleos del procesador por lo que los datos pueden
llegar a salir en desorden para evitar esto se usa .paralell() y
.forEachOrdered()
Operaciones terminales
Estos son métodos que alteran o interactúan con el stream
pero que no devuelven otro stream por lo que ya no es posible
hacer más Chaining
anyMatch, allMAtch noneMatch
estas 3 evalúan a los elementos del Stream
con un Predicate sus restricciones las indica su nombre
findFirst , findAny
Si están ordenados previamente los datos del stream
finFIrst retorna el primer dato y si no funciona como any
devolvendo cualquier dato presente
Devuelve un Optional
min max
estas evalúan de dos en dos datos con el comparator(una lambda)
y te da el valor de todo el stream ya sea el min o el max
reduce
binary accumulator
aplica la operación a cada elemento
valor BinaryOperator
Aplica el Operator a los elementos y en caso de no haber retorna el valor
binary function
funciona parecido al anterior solo que puede generar un tipo distinto
count
retorna el número de elementos en el stream
toArray
devuelve un arreglo con los elementos del stream
collect
convierte el stream en otra estructura de datos
foreach
hace lo que indique el consumer a todos los datos
Operaciones intermedias
Son operaciones que devuelven un stream por lo que permite hacer Chaining
filter
Recibe un Predicate y evalúa los elementos del stream
si devuelve true los conserva en el stream y si no los borra
map
Recibe un a lambda , toma como valores los elementos del stream y
los reemplaza con los resultados
flatMap
es parecido a map solo que puede lidiar con streams hechos de
otras estructuras de datos
distinct
básicamente elimina los elementos duplicados con ayuda de equals
limit
solo permite que haya x elementos en el stream si están en orden conserva los primeros
peek
Aplica un consumer a los elementos del stream
skip
es lo "contrario a limit" quita cierto número de elementos sólo que
skip cuenta cuántos números quita y los que sobra se quedan
sorted
te permite ordenar junto con comparable