Introducción a la PROGRAMACIÓN FUNCIONAL
El paradigma de programación funcional trata a la computación como la evaluación de funciones de matemáticas y evita el uso de estados mutable y datos modificables.
La programación imperativa centra sus soluciones en instrucciones paso a paso, mientras que la programación funcional se enfoca en cómo hacer las cosas, describiendo el problema en términos de transformaciones de datos mediante el empleo de funciones.
Sus características principales son las siguientes:
- Funciones como elementos de primera clase, las funciones pueden ser pasadas como argumentos, devueltas como resultados y asignadas a variables, por ejemplo:
Function areaCuadrado = x -> x*x;
System.out.println (areaCuadrado.apply(8)); //64 - Inmutabilidad, los datos son modificados después de su creación, en lugar de cambiar un valor, se crean nuevos valores, por ejemplo:
List numeros = Arrays.asList(1, 2, 3);
List duplicados = numeros.stream()
.map(x -> x * 2)
.toList(); // Nuevo objeto creado
En este caso las expresiones generan una nueva lista llamada duplicados, en la cual cada elemento de la lista numeros es multiplicado por 2, es decir duplicados contendrá los elementos [2,5,6].
.stream() convierte la lista numeros en un flujo (stream) de elementos.
.map(x -> x*2) aplica una función de mapeo a cada elemento del flujo multiplicándolo por dos.
.toList() recopila los elementos mapeados en una nueva lista (duplicados), con los resultados obtenidos.
- El uso de expresiones lambda.
Desde la versión 8 de Java, se introdujo una nueva sintaxis con el nombre de expresiones lambda, lo que permite implementar interfaces funcionales, de manera concisa y funcional, lo cual permite simplificar la escritura del código, cuando se trabaja con la programación funcional.
// La sintaxis básica de una expresión lambda es
(parámetros) -> { cuerpo de la expresión }
//Si el cuerpo es una sola línea, no se necesitan las llaves {}.
//SI no hay parámetros, se usan los paréntesis vacíos ().
Por ejemplo: vamos definir una función anónima que emplea una expresión lambda:
//Creamos una lista del tipo List llamada palabras que contenga tres elementos “Java”, “lambda” y //“Funcional”
List palabras = Arrays.asList(“Java”, “Lambda”, “Funcional”);
//Ahora utilizaremos una expresión lambda para iterar y procesar cada elemento de la lista
palabras.forEach(palabra -> System.out.println(palabra));
foreach es un método de interfaz Iterable que permite iterar sobre cada uno de los elementos de la lista
palabra -> System.out.println(palabra) es una expresión lambda que se ejecuta para cada elemento de la lista palabras.
- Funciones puras, este tipo de funciones no tienen efectos secundarios y siempre devuelven el mismo resultado para los mismos argumentos, por ejemplo:
Function sumarUno = x -> x + 1; - Interfaz Funcional, este tipo de interfaz contiene solo un método abstracto, se emplean con como tipos de datos para las expresiones lambda y los métodos de referencia, por ejemplo: La interfaz funcional Function toma un argumento del tipo T y devuelve un valor tipo R, de tipos de datos.
@FunctionalInterface
interface MiInterfazFuncional {
void ejecutar();
} - Recursión, en lugar de emplear bucles, se emplea la recursión para iterar, por ejemplo:
public int factorial(int n) {
return (n == 0) ? 1 : n * factorial(n – 1);
} Esta es una función recursiva para calcular la factorial de un número. - Evaluación perezosa (lazy evaluation), es una técnica que se emplea en los lenguajes de programación donde las expresiones no se evalúan hasta que su valor es realmente necesario.
//Crear una lista de enteros llamada numeros con los valores {1,2,3,4,5]
List numeros = Arrays.asList(1, 2, 3, 4, 5);
//Convertir la lista a stream
numeros.stream()
//Aplicar un filtro a los elementos del stream para que solo los elementos mayores que 2 pasen, //empleando una expresión lambda en donde la variable x represente cada elemento de stream.
.filter(x -> x > 2)
// Realizar una búsqueda de primer elemento que cumpla la condición
.findFirst(); // Solo evalúa hasta encontrar el primer elemento que cumple la condición.
Ventajas de la programación funcional:
a) Código más conciso y legible,
b) Menos errores,
c) Mayor facilidad para paralelizar, es decir dividir un problema en partes más pequeñas que se pueden ejecutar simultáneamente y
d) Reutilización de código
