Hero image
Inicio > Blog > Post

Programación funcional en Java

Introducción

La programación funcional es un paradigma que ha ganado popularidad en los últimos años debido a sus ventajas en cuanto a legibilidad, mantenibilidad y concurrencia. A partir de Java 8, este lenguaje incorporó características funcionales, permitiendo un estilo de programación más declarativo y expresivo.

En este artículo, aprenderás los conceptos clave de la programación funcional y cómo aplicarlos en Java.

¿Qué es la programación funcional?

La programación funcional es un paradigma de programación inspirado en las funciones matemáticas que se fundamenta en dos conceptos principales: la inmutabilidad de los datos y la composición de funciones puras. En este enfoque, las variables mantienen un estado constante a lo largo de la ejecución del programa (son inmutables), lo que significa que en lugar de modificar valores existentes, se crean nuevas instancias con los cambios deseados.

Este paradigma trata las funciones como ciudadanos de primera clase, eso permite que las funciones sean asignadas a variables, pasadas como argumentos y retornadas por otras funciones, lo que facilita la creación de código más predecible, mantenible y naturalmente adaptado para la computación paralela.

Los programas se construyen mediante la composición de expresiones y funciones que, al igual que las funciones matemáticas, siempre producen el mismo resultado para los mismos argumentos de entrada, sin efectos secundarios.

Analogía funciones con una cinta transportadora

💡Ejemplo: Imagina que entras a un restaurante de sushi con una cinta transportadora. Cada plato (dato) se mueve a lo largo de la cinta (nuestro pipeline). Los chefs (funciones) preparan y transforman esos platos sin cambiar la receta original. Al final, tú (la operación terminal) eliges lo que quieres comer. Así funciona la programación funcional: transforma datos sin modificar la fuente original.

Diferencias clave entre programación imperativa y funcional

CaracterísticaImperativa (clásica)Funcional
EstiloCómo hacer algoQué hacer
Estado mutableComúnEvitado
Estructuras de controlBucles, condicionalesFunciones y expresiones
Uso de efectos secundariosFrecuenteMínimo

Ejemplo en programación imperativa:

List<String> nombres = Arrays.asList("Ana", "Pedro", "Luis", "Maria");
List<String> nombresEnMayusculas = new ArrayList<>();
for (String nombre : nombres) {
    nombresEnMayusculas.add(nombre.toUpperCase());
}
System.out.println(nombresEnMayusculas);

El mismo ejemplo en programación funcional:

List<String> nombres = Arrays.asList("Ana", "Pedro", "Luis", "Maria");
List<String> nombresEnMayusculas = nombres.stream()
    .map(String::toUpperCase)
    .toList();

System.out.println(nombresEnMayusculas);

Conceptos clave de la programación funcional

1. Funciones puras

Una función pura es aquella cuyo resultado solo depende de sus argumentos y no tiene efectos secundarios.

Ejemplo de función pura:

public int suma(int a, int b) {
    return a + b;
}

Esta función siempre dará el mismo resultado en otras palabras podemos predecir el resultado para los mismos argumentos y no modifica variables externas.

2. Inmutabilidad

En programación funcional se evita modificar variables o estructuras de datos una vez creadas.

Ejemplo SIN inmutabilidad:

List<String> lista = new ArrayList<>();
lista.add("Hola");
lista.add("Mundo");

Ejemplo CON inmutabilidad:

List<String> lista = List.of("Hola", "Mundo");

3. Funciones de orden superior

Son funciones que reciben otras funciones como argumento o las retornan como resultado.

Ejemplo de función de orden superior:

public static void aplicarFuncion(List<Integer> numeros, Function<Integer, Integer> funcion) {
    numeros.forEach(n -> System.out.println(funcion.apply(n)));
}

public static void main(String[] args) {
    List<Integer> lista = List.of(1, 2, 3, 4);
    aplicarFuncion(lista, n -> n * 2); // Multiplica cada número por 2
}

4. Expresiones lambda

Las expresiones lambda permiten definir funciones de manera concisa.

Ejemplo de expresión lambda:

Function<Integer, Integer> cuadrado = x -> x * x;
System.out.println(cuadrado.apply(5)); // 25

5. Interfaces funcionales

Java proporciona varias interfaces funcionales en el paquete java.util.function.

InterfazDescripciónEjemplo de Uso
Predicate<T>Prueba una condición sobre Tn -> n > 10
Function<T, R>Transforma T en Rx -> x * 2
Consumer<T>Ejecuta una acción sobre Tx -> System.out.println(x)
Supplier<T>Proporciona una instancia de T() -> new Producto()

Ejemplo con Predicate:

Predicate<Integer> esPar = n -> n % 2 == 0;
System.out.println(esPar.test(4)); // true

Conclusión

La programación funcional en Java permite escribir código más claro, reutilizable y mantenible. A lo largo de esta serie de blogs, profundizaremos en su aplicación con la API Stream, optimizando la forma en que trabajamos con colecciones de datos.

En el próximo blog:

Nos enfocaremos en Expresiones lambda e interfaces funcionales, fundamentales para entender los Streams en Java.

📘 Recursos adicionales:


Mis redes sociales

Si tienes alguna sugerencia o comentaria puedes contactarme en mis redes sociales.