Funciones y predicados son solo una de las tantas cosas que ofrece este paradigma. Este enfoque tiene como consecuencia una legibilidad del código bastante buena. Pero antes de entrar en ese terreno debemos entender que existen varios enfoques a la hora de programar y uno de los más conocidos son el imperativo, declarativo, multiparadigma y reactiva. Nos vamos a centrar en este artículo en los enfoques imperativo y declarativo.

Muchos programadores escriben su código de una forma imperativa donde específicas y defines cada detalle de lo que tiene que hacer tu código. Sin embargo, cuando programamos de forma declarativa, simplemente decimos que es lo que queremos hacer en vez de definir el cómo.

Vamos a ver un ejemplo, aunque no entraremos en detalles de que es cada cosa. El objetivo es visualizar como el código legible va surgiendo de forma natural.

Supongamos que tenemos una clase persona y una lista de personas, donde cada persona tiene un nombre y un género.

    public class Persona {
        private final String nombre;
        private final Genero genero;

        Person(String nombre, Genero genero) {
            this.nombre = nombre;
            this.genero = genero;
        }

        @Override
        public String toString() {
            return "Persona {" +
                    "nombre=" + nombre +
                    ", genero=" + genero +
                    '}';
        }
    }

    enum Genero {
        MASCULINO, FEMENINO
    }
    public static void main(String[] args) {
    
        List<Persona> personas = List.of(
            new Persona("Jose", MASCULINO),
            new Persona("Maria", FEMENINO),
            new Persona("Liliana", FEMENINO),
            new Persona("Fernando", MASCULINO),
            new Persona("Alicia", FEMENINO)
        );
        
    }

Si queremos filtrar e imprimir esa lista de personas por género, con un enfoque imperativo, normalmente lo haríamos de la siguiente manera.

     List<Persona> mujeres = new ArrayList<>();

     for (Persona persona : personas) {
         if (FEMENINO.equals(persona.genero)) {
             mujeres.add(persona);
         }
     }

     for (Persona mujer : mujeres) {
         System.out.println(mujer);
     }

Sin embargo, si tomamos un enfoque más declarativo, de que es lo que queremos hacer, entonces el código sería parecido al siguiente.

Apunte, a grandes rasgos para entender el código, un predicado es una interfaz funcional que recibe una condición a cumplir.

    Predicate<Persona> personaPredicate = 
                persona -> FEMENINO.equals(persona.genero);

    List<Persona> mujeres = personas.stream()
            .filter(personaPredicate)
            .collect(Collectors.toList());
            
    mujeres.forEach(System.out::println);

Como podemos observar el código resulta más legible. Aunque en ejemplos pequeños no se pueda apreciar del todo, en problemas más complejos se nota mucho.

Para conocer más sobre este paradigma te invito al curso de Java Lambdas - Programación funcional que te enseña todo lo esencial para que aprendas a programar mejor.