Introducción a la programación Funcional

1

¿Qué es la Programación Funcional?

Entendiendo las partes de la programación funcional

2

¿Qué es una función en Java?

3

Funciones como ciudadanos de primera clase

4

Funciones puras

5

Entendiendo los efectos secundarios

6

Funciones de orden mayor

7

Funciones lambda

8

Inmutabilidad

Functional Programming en Java

9

Repositorio del curso

10

Configuración del entorno de trabajo

11

Revisando el paquete java.util.function: Function

12

Revisando el paquete java.util.function: Predicate

13

Revisando el paquete java.util.function: Consumer y Supplier

14

Revisando el paquete java.util.function: Operators y BiFunction

15

Entendiendo dos jugadores clave: SAM y FunctionalInterface

16

Operador de Referencia

17

Analizando la inferencia de tipos

18

Comprendiendo la sintaxis de las funciones lambda

19

Usando metodos default en nuestras interfaces

20

Dándole nombre a un viejo amigo: Chaining

21

Entendiendo la composición de funciones

Optional y Streams: Datos mas interesantes

22

La clase Optional

23

Entendiendo los Streams

24

¿Qué son los Stream listeners?

25

Operaciones y Collectors

26

Streams de tipo específico y Paralelismo

27

Operaciones Terminales

28

Operaciones Intermedias

29

Collectors

Todo junto: Proyecto Job-search

30

job-search: Un proyecto para encontrar trabajo

31

Vista rápida a un proyecto de Gradle

32

Revisando las opciones para nuestro CLI

33

Librerías adicionales para nuestro proyecto

34

Entendiendo la API de jobs

35

Diseñando las Funciones Constructoras de nuestro Proyecto

36

Agregando validaciones de datos

37

Diseñando las funciones de transformacion de datos

38

Creando flujos extras de transformación de Datos

Conclusiones

39

Un repaso a lo aprendido

No tienes acceso a esta clase

¡Continúa aprendiendo! Únete y comienza a potenciar tu carrera

Aprovecha el precio especial y haz tu profesión a prueba de IA

Antes: $249

Currency
$209
Suscríbete

Termina en:

0 Días
1 Hrs
46 Min
47 Seg

Revisando el paquete java.util.function: Consumer y Supplier

13/39
Recursos

¿Qué son los consumidores y proveedores en la programación funcional?

La programación funcional ofrece herramientas sorprendentes para gestionar y procesar datos de manera eficaz. Dos de estas herramientas son las interfaces Consumer y Supplier. Estas interfaces están diseñadas para consumir y proveer datos, respectivamente, y son una parte fundamental de muchos lenguajes de programación, incluyendo Java.

¿Cómo funciona un consumidor?

Un Consumer es una interfaz genérica que se utiliza para realizar operaciones sobre un objeto de tipo específico. No retorna ningún valor, sino que toma un objeto, lo consume y realiza ciertas acciones sobre él.

Ejemplo de código:

Supongamos que tenemos una clase denominada CommandLineArgs, que contiene los elementos pasados al programa desde la terminal.

public class CommandLineArgs {
    private boolean displayHelp;

    public boolean isDisplayHelp() {
        return displayHelp;
    }
}

// Uso de Consumer
import java.util.function.Consumer;

public class CommandLineUtils {
    public static void displayHelpIfRequested(CommandLineArgs args) {
        Consumer<CommandLineArgs> consumerHelp = argsData -> {
            if (argsData.isDisplayHelp()) {
                System.out.println("El manual ha sido solicitado.");
            }
        };
        consumerHelp.accept(args);
    }
}

Este enfoque permite, por ejemplo, consumir una lista de archivos y realizar acciones como borrar cada archivo a medida que se procesa.

¿Qué es un proveedor (Supplier)?

Por otro lado, un Supplier es una interfaz genérica que se encarga de generar datos de un cierto tipo. A diferencia del Consumer, el Supplier no recibe argumentos y se utiliza principalmente para generar y proporcionar datos cuando sea necesario.

Ejemplo de código:

Continuando con nuestra clase CommandLineArgs, podemos usar un Supplier para crear nuevas instancias cuando se requiera.

import java.util.function.Supplier;

public class SupplierExample {
    public static CommandLineArgs provideArgs() {
        Supplier<CommandLineArgs> supplier = CommandLineArgs::new;
        return supplier.get();
    }
}

El Supplier permite, por ejemplo, generar configuraciones o crear archivos bajo demanda, eliminando la necesidad de una configuración completa desde el inicio.

¿Por qué son útiles estas interfaces?

Estas interfaces son extremadamente útiles en muchos escenarios:

  • Eficiencia: Permiten la creación y gestión de datos solo cuando es necesario, optimizando el uso de recursos.
  • Flexibilidad: Facilitan la creación de algoritmos modulares donde las operaciones sobre datos se pueden definir y modificar de forma independiente.
  • Reutilización de código: Los Consumers y Suppliers pueden ser usados en múltiples contextos, promoviendo la reutilización del código.

¿Cómo se integran los consumidores y proveedores en proyectos más grandes?

Estas interfaces cobran aún más relevancia al integrarse en proyectos complejos. Permiten a los desarrolladores definir claramente las operaciones tanto en la entrada como en la salida de datos dentro del flujo de un programa.

  • Operaciones sobre colecciones: Por ejemplo, un Consumer puede ser usado para procesar elementos de una lista secuencialmente.
  • Generación dinámica de datos: Un Supplier es ideal para crear objetos que deben inicializarse justo antes de su uso, como configuraciones que dependen del contexto.

La introducción de estos conceptos en nuestro arsenal de herramientas de programación amplía significativamente nuestras capacidades para diseñar soluciones eficientes y efectivas. ¡Sigue explorando estas herramientas y descubriendo más sobre la programación funcional! Cada pequeño paso te acercará a un manejo más completo y preciso de la programación moderna.

Aportes 28

Preguntas 5

Ordenar por:

¿Quieres ver más aportes, preguntas y respuestas de la comunidad?

No me quedaron muy claros los conceptos de Consumer y Supplier asi que investigando y con lo que dijo Sinue en la clase puedo complementar.

Consumer: Es una expresion lambda que acepta un solo valor y no devuelven valor alguno.
Ejemplo: Una funcion que reciba una lista de archivos y borre cada uno de ellos, sin devolver nada.

Supplier: Es una expresion que no tienen parámetros pero devuelven un resultado.
Ejemplo: Se crea un supplier de tipo CLIArguments llamado generator que no recibe ni un parametro pero que crea un nuevo objeto CLIArguments y retorna generator, Se pueden crear archivos bajo demanda.

Use el concepto anterior del predicate y coloque un ejemplo de como usar el generador con streams.

Consumer

Utilizando la interfáz Consumer<T> , es posible definir funciones que reciban un parámetro tipo T y realicen determinadas operaciones con él pero sin retornar ningún dato.

Por ejemplo, se puede definir el Consumer guardarPersona que recibe una entidad Persona y simplemente la almacena en la base de datos.

public void save(Persona persona) {
    Consumer<Persona> guardarPersona = p -> {
        if (p != null) {
            this.database.insert(p);
        }
    };

    guardarPersona.accept(persona);
}

Utilizar Consumer es útil para evitar duplicar código dentro de una misma función, por ejemplo, cuando se necesita hacer una serie de acciones sobre un objeto más de dos veces, y por alguna razón no es posible evitar duplicar el código.


Supplier

Utilizando la interfáz Supplier<T> , es posible definir funciones que no reciba ningún parámetro pero sí retornen un objeto de tipo T.

Por ejemplo, se puede definir el Supplier generador que retorna una nueva instancia de la entidad Persona.

public Persona getEmpty() {
    Supplier<Persona> generador = () -> new Persona();

    return generador.get();
}

Utilizar Supplier es útil para evitar duplicar código dentro de una misma función, por ejemplo, cuando se necesita instanciar un objeto rellenando varios atributos con un valor redefinido en más de dos lugares, y por alguna razón no es posible evitar duplicar el código.

Les comparto una lectura donde puden ir si no les quedó muy claro Predicate, Consumer, Supplier. Link al blog

Por cierto, cuando un if tiene una sola linea, podemos evitar las llaves.
Funciona exactamente igual pero queda mas limpio.

if(cliArguments1.isHelp()) System.out.println("Manual solicitado");

Además, en la función lambda se puede reemplazar el constructor de clase por una referencia de método usando ::

Supplier<CLIArguments> generator = CLIArguments::new;

Me estoy emocionando mucho con este tema.

Un buen escenario para poner en práctica **Consumer **y Supplier es cuando mandas a llamar una lista de entidades de una tabla en BD. Con **Consumer **conviertes las entidades en DTOS y después lo invocas desde un **Supplier **para que éste genere la lista final.

En lo personal considero que el curso esta manejando un nivel de velocidad muy alto, te explican los conceptos muy a la ligera, con ejemplos complejos y no da espacio a la compresión del tema visto en cada clase.

las funciones de tipo consumer. pueden ser del tipo impuras, dado que , como en el ejmplo que dio el profe, podrias ir borrando archivos dependiendo de los datosqeu le vayan llegando. Pir lo cual generariaefectos secundarios.

Consumer:
Se utiliza para ejecutar la misma operación en un tipo de objeto especifico.

Supplier:
Se utiliza para generar objetos de un tipo.

En apache net beans, puedes mantener presionado Ctrl y hacer click en una Clase que utilices, cuando lo hagas net beans te va a llevar a la definición de esa Clase

Consumer es una Interfaz genérica, función que tiene como 1 solo parámetro.
Tiene como método: accept
<-------->
Supplier es otra interfaz genérica, función que que encarga de generar datos, proveer datos. 1 solo parámetro.

Tiene como método get.

Estoy Waaaouh!! que buen tema.!!!

```java import java.util.Arrays; import java.util.function.Consumer; import java.util.function.Predicate; import java.util.function.Supplier; record Args(boolean isHelp) { } class Utils { static void showHelp(Args args) { Predicate<Args> isHelp = Args::isHelp; Consumer<Args> consumerHelper = args1 -> { if (isHelp.test(args)) System.out.println("Required manual"); }; consumerHelper.accept(args); } static Args generateArgs(boolean arg) { Supplier<Args> argsSupplier = () -> new Args(arg); return argsSupplier.get(); } } public class Consumer_Supplier { public static void main(String[] args) { String[] arguments = {"true", "false", "true"}; Arrays.stream(arguments) .map(Boolean::parseBoolean) .forEach(value -> Utils.showHelp(Utils.generateArgs(value))); } } ``` import *java.util.Arrays*; import *java.util.function.Consumer*; import *java.util.function.Predicate*; import *java.util.function.Supplier*; record *Args*(boolean isHelp) { } class *Utils* { static void *showHelp*(*Args args*) { *Predicate*<*Args*> isHelp = *Args*::*isHelp*; *Consumer*<*Args*> consumerHelper = *args1* -> { if (isHelp.*test*(args)) *System*.out.*println*("Required manual"); }; consumerHelper.*accept*(*args*); } static *Args generateArgs*(boolean *arg*) { *Supplier*<*Args*> argsSupplier = () -> new *Args*(arg); return argsSupplier.*get*(); } } public class *Consumer\_Supplier* { public static void *main*(*String*\[] *args*) { *String*\[] arguments = {"true", "false", "true"}; *Arrays*.*stream*(arguments) .*map*(*Boolean*::*parseBoolean*) .*forEach*(*value* -> *Utils*.*showHelp*(*Utils*.*generateArgs*(*value*))); } }

¡Hola! Investigando sobre este tema, el próposito de los Consumer es proporcionar una forma de realizar una operación en un objeto sin necesidad de devolver un resultado y de un Supplier es proporcionar valores de manera dinámica y bajo demanda.

Sinuhe en varias oportunidades haces referencia a los métodos pero lo llamas funciones, lo correcto creo que es que creas métodos dentro los cuales creas funciones

Ahora en vez de:
Supplier<CLIArguments> generator = () -> new CLIArguments();

Podemos hacer:
Supplier<CLIArguments> generator = CLIArguments::new;

Utilizando methos reference.

Un consumer recibe un parametro pero NO retorna nada (a diferencia de Function, Predicate o Supplier que si devuelven algo).

Un supplier no recibe ningun parametro, pero retorna algo.

Les dejo una referencia donde se ve una aplicación del Supplier bajo el patrón factory.

https://refactorizando.com/java-supplier-interface/

Saludos!

Excelente

Uso práctico del consumer, borrado de archivos o reemplazar

En resumen (o por lo que entendi) estas funciones nos permiten consumir una serie de datos que le pasemos sin tener que construir una estructuras con ciclos, y nos permite de igual forma realizar operaciones comunes sobre una serie de parámetros de manera mas simplificada.

Muy bien, entonces a partir del Consumer vamos a poder realizar acciones a una serie de datos de forma rapida en cambio el Supplier nos ayudara a generar datos en base a las características que le brindemos a los parámetros que recibe.

Consumer<T> is an in-built functional interface introduced in Java8 in the java.util.function package. The consumer can be used in all contexts where an object needs to be consumed, i.e. taken as an input and some operation is to be performed on the object without returning any result. A common example of such an operation is printing where an object is taken as input to the printing function and the value of the object is printed. Since Consumer is a functional interface, hence it can be used as the assignment target for a lambda expression or a method reference.

Supplier<T> is an in-built functional interface introduced in Java8 in the java.util.function package. The supplier can be used in all contexts where there is no input but an output is expected. Since Supplier is a functional interface, hence it can be used as the assignment target for a lambda expression or a method reference.

Sigamos

Excelente 😃

Lo que entendí es que estos son usados cuando solo quieres usar un tipo de dato, ya sea el de entrada o de salida:
Function<Entrada,Salida>
Consumer<Entrada>
Supplier<Salida>