Qué es la programación funcional y por qué deberías usarla

La programación funcional puede ayudarnos a crear software más robusto, mantenible y fácil de testear. Quizás hayas empezado a oír hablar de lenguajes de programación funcional como Scala, Haskell o Lisp, pero quizá no sepas todavía que Java en su versión 8 permite usar la potencia de la programación funcional sin abandonar su orientación a objetos.

Pero, ¿qué hace que lenguajes como C, C++ o Java adopten la programación funcional?

programacion-funcional

Como dijo C.A.R. Hoare:

“Hay dos formas de diseñar software: una forma es hacerlo tan simple que obviamente no haya deficiencias, y la otra es hacerlo tan complicado que no haya deficiencias obvias. El primer método es mucho más difícil”.

Desde que empiezas a programar con Java te enseñan qué es un lenguaje de programación orientado a objetos y que Java es uno de ellos. Te enseñan a programar de manera imperativa y es como has programado desde entonces. Con estas herramientas tienes que crear la mejor solución posible y hasta hoy no ha ido mal. Pero, ¿y si te digo que hay una forma mejor de llegar a esas soluciones?

En la programación declarativa no definimos cómo queremos resolver un problema, sino que definimos cuál es el problema. Un ejemplo sencillo para comparar estas dos formas de programar es encontrar en una lista de colores si tenemos el color “red”:

boolean hasRed = false;
for (String color : colors) {
   if (color.equals("red")) {
      hasRed = true;
      break;
   }
}

System.out.println("Has color red? " + hasRed);

Aquí vemos cómo estamos definiendo la manera de resolver el problema. Esta forma de hacerlo es muy verbosa y nos hace tener que definir una variable hasRed para marcar si se ha encontrado o no, lo que hace que este código sea un poco “feo”.

pf1

¿Y si te digo que ya has usado la forma declarativa?:

System.out.println(“Has color red?:” + colors.contains(“red”));

Esta solución es más concisa, más clara y más fácil de entender por cualquier persona. No sabemos la implementación que estamos usando ya que eso es cosa del código que hay por debajo. Lo que sí sabemos es exactamente lo que hace ese código: nos dice si colors contiene “red”. Por suerte, para este ejemplo el API de Java nos provee del método contains, que nos ayuda a hacer nuestro código más legible, pero no siempre tendremos esa suerte.

En los casos en los que tengamos que crear nuestros propios métodos podemos usar la programación funcional, que es declarativa y por tanto nos puede ayudar a hacer nuestro código más limpio. Veamos un ejemplo de cómo podemos mejorar nuestro código usando programación funcional.

Dada una lista de números decimales queremos descontar un 20% a todos los que sean mayores de 25 y sumarlos:

BigDecimal sum = BigDecimal.ZERO;
for (BigDecimal number : numbers) {
   if (number.compareTo(BigDecimal.valueOf(25)) > 0) {
      sum = sum.add(number.multiply(BigDecimal.valueOf(0.8)));
   }
}

System.out.println("Total: " + sum);

Seguro que ese código es muy familiar para todos. Como vemos, estamos creando una variable sum donde vamos cambiando su valor en función de las condiciones que hemos definido en el enunciado.

Veamos ahora cómo escribir ese código de una manera mucho más clara de forma funcional primero en Java 8:

final BigDecimal sum =
   numbers.stream()
      .filter(number -> number.compareTo(BigDecimal.valueOf(25)) > 0)
      .map(number -> number.multiply(BigDecimal.valueOf(0.8)))
      .reduce(BigDecimal.ZERO, BigDecimal::add);
        
System.out.println("Total: " + sum);

Y el mismo código usando Scala:

val sum = numbers.filter(_ > 25)
      .map(_ * .8)
      .sum
    println(sum)

Este código se puede “leer”. Cualquier persona que se ponga delante de él puede leerlo de la siguiente forma:

  • Filtrar los números mayores de 25.
  • Asignar a cada número un número igual a su 80%.
  • Usar el método add para reducir esa lista.

Estamos declarando el problema mientras escribimos su implementación en el código. Lo único que tenemos que hacer es coger los requisitos de la funcionalidad que queremos implementar y escribirlos. De esta manera si alguna vez cambian o si algún otro compañero tiene que mirar nuestro código será muy sencillo saber qué es lo que está haciendo ahora y, por lo tanto, añadir las nuevas especificaciones.

pf2

Esta es una pequeña introducción a la programación funcional. Te aconsejo que sigas buscando más acerca de las novedades en Java 8 sobre este paradigma de programación y verás cómo tu código se vuelve más simple y más conciso, haciendo que tenga menos fallos y que los que tenga sean más sencillos de encontrar y corregir.

Llevo programando desde los 8 años cuando mis padres se compraron un Amstrad CPC 6128. Desde entonces no he parado y me encanta aprender lenguajes nuevos y aplicar las 3 R (Reutilizar, Reducir, Refactorizar) a los proyectos donde estoy. Actualmente trabajo como Arquitecto de Soluciones en Paradigma.

Ver toda la actividad de Rubén García Becerro

Recibe más artículos como este

Recibirás un email por cada nuevo artículo.. Acepto los términos legales

Comentarios

  1. Ximo Dante dice:

    Hola Rubén,
    primeramente felicitarte por tu esclarecedor artículo. La verdad es que Java siempre ha pecado de ser muy verboso. Creo que el tema de la inferencia del tipado de variables, no solo se debería aplicar a los streams, sino a muchas mas partes de Java. Y ya puestos, creo que ya no sería Java. Creo que estamos transformando Java en otro lenguaje del ecosistema de la jvm, ya que se han inventado buenos lenguajes, pero por temas de iniercia, están quedando en la cuneta. Gracias

Escribe un comentario