La programación funcional es un paradigma de programación basado en funciones matemáticas, los lenguajes de programación funcional son aquellos lenguajes donde las variables no tienen estado. No hay cambios en estas a lo largo del tiempo, son inmutables (no pueden cambiarse los valores a lo largo de la ejecución), además los programas se estructuran componiendo expresiones que se evalúan como funciones.

Dentro de los lenguajes funcionales tenemos a lisp, scheme, clojure, haskell, etc. que son lenguajes estrictamente funcionales. Java vendría siendo un lenguaje híbrido que va a componerse del lenguaje imperativo que es el que nosotros conocemos, y ahora con las nuevas características de programación funcional que se incorporaron.

Uno de los ejemplos más comunes de la programación funcional es que las instrucciones cíclicas como el for, el while y el do while no existen. Todo se procesa usando recursividad y funciones de alto orden. Sin embargo en Java vamos a seguir teniendo las dos opciones, vamos a continuar teniendo nuestras funciones cíclicas que siempre hemos usado como programadores de Java y ahora también estas nuevas   funciones de alto orden que nos van a permitir iterar a través de una serie de colecciones y conjuntos de datos, apoyándonos en las expresiones lambda y en una serie de métodos que son incorporados en las versiones de java.

En los lenguajes estrictamente funcionales no hay tipos de datos. En Java no vamos a tener exactamente lo mismo, pero por medio de las expresiones lambda vamos a poder hacer uso de la inferencia de tipos o más bien dentro de  las expresiones lambda vamos a poder prescindir de declarar los tipos de datos y vamos a dejar ese trabajo al compilador por medio de la inferencia de tipos.

Para lograr todo esto Java a incorporado nuevas características como las expresiones lambda, métodos referenciados y las interfaces funcionales.

Veamos un ejemplo

- Conocer cuántos números mayores a 10 hay en la Lista

List<Integer> numeros = List.of(11, 8, 9, 15, 39, 1, 4, 83);

- Resolvemos la problemática con ciclos y condicionales, enfoque declarativo

// Declarativo
List<Integer> numeros = List.of(11, 8, 9, 15, 39, 1, 4, 83);
	
int contador = 0;

for (int numero: numeros) {
	if(nuemero > 10){
		contador ++;
	}
}

System.out.println(contador);

- El enfoque imperativo sería el siguiente

// Imperativo
Long resultado = numeros.stream().filter(num -> num > 10).count():
System.out.println(resultado);

Como podemos observar con la programación funcional las líneas de código se reducen y nuestro código se muestra más legible.

En la implementación imperativa se podría concluir que es funcional, ya que delega el control de flujo y condiciones a las funciones filter y count.

Expresión lambda

Una expresión lambda está caracterizada o su sintaxis es:

parámetro → cuerpo de la expresión lambda

Una expresión lambda representa el método abstracto de una interfaz funcional, una interfaz funcional es aquella que solo tiene un método abstracto, puede tener cualquier cantidad de métodos default o estáticos, pero solamente puede tener un método abstracto. Este método puede ser representado por una expresión lambda.

// Clase principal
public class lambdaFunction {
	
	// Se declara la interface
	interface operacion {
		// el metodo abstracto
		public double suma(double x, double y);
	}

	public static void main(String[] args) {
		// Expresion lambda
		operacion l = (x, y) -> x + y;
		System.out.println(l.suma(8, 30));
	}
}

Interfaces funcionales

Una interfaz funcional es aquella que solo tiene un método abstracto, podemos utilizar métodos default, métodos estáticos y métodos heredados de la clase object y declararlos como métodos abstractos.

// Clase principal
public class lambdaFunction {
	
	// Anotacion para declara la interface
	@FunctionalInterface
	interface operacion {
		// el metodo abstracto
		public double suma(double x, double y);
	}

	public static void main(String[] args) {
		// Expresion lambda
		operacion l = (x, y) -> x + y;
		System.out.println(l.suma(8, 30));
	}
}

Si la interface que estamos declarando contiene la Anotación @FunctionalInterface y esta no cumple con los criterios para que sea una interfaz funcional nos dará un error de compilación, esto nos ayuda y es una buena práctica para desarrollar correctamente. Cabe mencionar que  una interface con un solo método abstracto como lo hemos comentado sigue siendo una interfaz funcional aunque no tenga la Anotación @FunctionalInterface.

Métodos referenciados

Hasta ahora lo que sabemos y conocemos de la programación funcional es que las expresiones lambda sirven para reemplazar los métodos anónimos en el caso de las interfaces funcionales. Algunas veces sin embargo una expresión lambda no hace otra cosa más que llamar a un método que ya existe, en estos casos podría ser más claro referirnos al método que ya existe por su nombre.

Los métodos referenciados nos permiten referirnos a los métodos que ya existen mediante su nombre.

import java.util.function.Consumer;

public class referenceMethods {
	
	public static void main(String[] args) {
		
		// utilizaremos en la interface Consumer que tiene un unico metodo denominado accept
		// el cual recibe un parametro y no devuelve nada
		Consumer<String> consumidor = x -> System.out.println(x);
		consumidor.accept("Bienvenido");
		
		procesar(x -> System.out.println(x), "Bienvenido2");
		
		// Pasamos como referencia una funcion que se encuentra en nuestro propio programa
		procesar(referenceMethods::saludar, "Bienvenido3");
	}
	
	public static <T> void procesar(Consumer<T> expresion, T mensaje) {
		expresion.accept(mensaje);
	}
	
	// Disponemos de otro metodo en la misma clase que cumple con el patron 
	// de la expresion lambda (reciba un parametro y no devuelva nada)
	public static void saludar(String saludo) {
		System.out.println("*****************************");
		System.out.println(saludo);
		System.out.println("*****************************");
	}
}

La programación funcional nos permite crear software mucho más legible y fácil de testear, de esta forma nos centramos en que estamos haciendo y no en cómo se está haciendo.

Finalmente, te te invitamos a que te pases a ver nuestro curso que Pogramación funcional con Lambdas, donde aprenderás desde cero a utilizar el API de Streams y las funciones Lambdas.