¡Acceso ilimitado 24/7 a todos nuestros libros y vídeos! Descubra la Biblioteca Online ENI. Pulse aquí
¡Acceso ilimitado 24/7 a todos nuestros libros y vídeos! Descubra la Biblioteca Online ENI. Pulse aquí
  1. Libros
  2. Java Spring
  3. La programación funcional
Extrait - Java Spring Construya aplicaciones reactivas con una arquitectura de microservicios en un entorno Jakarta EE
Extractos del libro
Java Spring Construya aplicaciones reactivas con una arquitectura de microservicios en un entorno Jakarta EE Volver a la página de compra del libro

La programación funcional

Introducción

Los elementos fundamentales de la programación funcional con lambdas incluyen los siguientes conceptos:

  • las expresiones lambda,

  • las interfaces funcionales,

  • los métodos de referencia,

  • las operaciones sobre los flujos,

  • la inmutabilidad,

  • las órdenes superiores de las funciones,

  • la reducción del bucle.

Las expresiones lambda

Las expresiones lambda son funciones anónimas que pueden utilizarse como valores. Estos permiten definir bloques de código cortos y concisos para realizar operaciones sobre los datos sin tener que crear clases separadas para las funciones.

Pueden utilizarse para definir una función anónima utilizando una sintaxis concisa. Por ejemplo, para definir una función que tome dos enteros como entrada y devuelve su suma, puede utilizar una expresión lambda:

// Definir la expresión lambda 
BinaryOperator<Integer> sumFunction = (a, b) -> a + b; 
 
// Utilizar la expresión lambda para calcular 
// la suma de dos enteros 
int result = sumFunction.apply(10, 20); 
 
// Output: Resultado de la suma: 30 
System.out.println("Resultado de la suma: " + result); 

Las interfaces funcionales

Las interfaces funcionales son interfaces que contienen un único método abstracto. Son esenciales para definir los tipos de parámetros y de retorno de las expresiones lambda. Entre las interfaces funcionales integradas en Java se encuentra Runnable, Callable, Comparator, Consumer, Predicate, etc.

Por ejemplo, la interfaz Runnable es una interfaz funcional que representa una tarea que se ejecutará de manera asíncrona:

 
// Definición de la interfaz funcional Runnable 
Runnable  task = () -> { 
  for (int i = 0; i < 5; i++) { 
    System.out.println("Tarea ejecutándose actualmente..."); 
  } 
}; 
  
// Ejecución de la tarea mediante un thread 
Thread thread = new Thread(task); 
thread.start(); 
   
// Espera a que el thread se termine 
thread.join(); 
} 

Los métodos de referencia

Los métodos de referencia permiten simplificar el uso de lambdas al permitir hacer referencia a métodos existentes por su nombre en lugar de escribir una expresión lambda completa.

Por ejemplo, para hacer referencia a un método estático, se puede utilizar un método de referencia:

// Definición de un método estático 
public static void printMessage(String message) { 
    System.out.println("Mensaje: " + mensaje); 
} 
 
// Uso de un método de referencia para referirse al 
// método estático  
Consumer<String> printer = ExampleClass::printMessage; 
  
// Mostrar : Mensaje: ¡Hola, mundo!   
printer.accept("¡Hola, mundo!"); 

Las operaciones sobres los flujos

Java 8 introdujo los flujos (streams), que permiten procesar las colecciones de datos de manera funcional. Los flujos ofrecen operaciones de transformación, de filtrado y de reducción, lo que permite efectuar tratamientos de datos de forma concisa y expresiva.

Por ejemplo, para filtrar los números pares de una lista y mostrarlos:

  List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5, 6, 7, 8, 9, 10); 
  
  numbers.stream() 
    .filter(n -> n % 2 == 0) // Filtra los números pares 
    .forEach(System.out::println); // Muestra los números pares 
} 

La inmutabilidad

La programación funcional favorece a la utilización de datos inmutables, es decir, que los datos no pueden modificarse una vez creados. Esto permite evitar efectos secundarios y hace que el código sea más predecible y seguro.

En Java, podemos utilizar clases inmutables para garantizar que los objetos no puedan modificarse una vez creados.

La inmutabilidad se indica mediante la palabra clave final.

Por ejemplo, para crear una clase inmutable que represente a una persona con un nombre y una edad:

final class Person { 
    private final String name; 
    private final int age; 
 
    public Person(String name, int age) { 
        this.name = name; 
        this.age = age; 
    } 
   
    // Métodos de acceso a propiedades (getters) 
    public String getName() { 
        return name; 
    } 
 
    public int getAge() { 
        return age; 
    } 
} 

La inmutabilidad presenta varias ventajas:

  • La coherencia de los datos: la inmutabilidad garantiza que los datos sean siempre...

Las órdenes superiores de las funciones

En programación funcional, las funciones pueden tratarse como objetos de primera clase, es decir, pueden pasarse como parámetros a otras funciones y devolverse como resultados.

Por ejemplo, para definir una función que tome una lista de números enteros y aplique otra función a cada elemento:

  @Test 
  public void testSquareFunction() { 
    List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5); 
   
    Function<Integer, Integer> squareFunction = n -> n * n; 
   
    List<Integer> squaredNumbers = numbers.stream() 
      .map(squareFunction) 
      .collect(Collectors.toList()); 
   
    assertEquals(Arrays.asList(1, 4, 9, 16, 25), squaredNumbers); 
  } 
  

La reducción del bucle

En lugar de utilizar los bucles tradicionales, la programación funcional fomenta el uso de funciones de reducción (reduce) para procesar las colecciones de datos. Esto reduce la complejidad del código y mejora su legibilidad.

Por ejemplo, para calcular la suma de todos los elementos de una lista de números enteros:

@Test 
public void testSum() { 
  List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5); 
   
  int sum = numbers.stream()   
    .reduce(0, (a, b) -> a + b); 
  
  assertEquals(15, sum); 
} 

Conclusión

Combinando estos elementos fundamentales, los desarrolladores de Java pueden sacar el máximo partido de la programación funcional con expresiones lambda para escribir código más conciso, fácil de mantener, legible y con mayor capacidad de respuesta, al mismo tiempo que aprovechan al máximo las características de Java 8 y versiones posteriores.