Skip to content
Menu
Laboratorios TERA Byte
  • Home
  • Quienes Somos
  • Política de privacidad
  • Contáctame
Laboratorios TERA Byte

Programación Funcional: Qué es y por qué importa

Posted on 13 August, 202514 August, 2025

Ir al post : Supplier post = () -> “Post 2”

  • Imperativo vs Funcional
  • Por qué usarlo
  • Conceptos clave que vamos a usar en la serie
  • Conclusión
  • Próximo paso: Post 2 – Lambda Expressions y Method References
  • Mini aplicación de práctica 💻

En Java solemos pensar en objetos, clases y métodos… pero desde Java 8 el lenguaje nos dio otra forma de escribir código: programación funcional.
No es magia ni moda pasajera, es un paradigma que hace tu código más expresivo, fácil de mantener y hasta más rápido de leer.


Imperativo vs Funcional

  • Imperativo → Tú dices cómo hacer algo, paso a paso.
  • Funcional → Tú dices qué quieres obtener, y el lenguaje se encarga del “cómo”.

Ejemplo rápido:

Imperativo:

Java
List<String> names = new ArrayList<>();
for (String name : people) {
    if (name.startsWith("A")) {
        names.add(name.toUpperCase());
    }
}
System.out.println(names);
// Resultado: [ANA, ALBA]

Funcional (Java 8+):

Java
List<String> names = people.stream()
    .filter(name -> name.startsWith("A")) // Filtra ["Ana", "Alba"]
    .map(String::toUpperCase)             // Convierte a ["ANA", "ALBA"]
    .toList();

System.out.println(names);
// Resultado: [ANA, ALBA]

💡 Menos código, más declarativo.


Por qué usarlo

  • Menos código repetitivo → Adiós a los bucles infinitos.
  • Más expresivo → El código dice qué haces, no cómo lo haces.
  • Más fácil de paralelizar → Streams permiten procesamiento concurrente con poco esfuerzo.
  • Más fácil de testear → Las funciones puras no dependen de estado externo.

Conceptos clave que vamos a usar en la serie

  1. Lambdas (Expresiones Lambda)

Son funciones anónimas (sin nombre) que puedes asignar a variables o pasar como argumento.
En lugar de escribir una clase completa solo para implementar un método, usas una lambda más compacta.

Ejemplo clásico:
Antes (clase anónima):

Java
Comparator<String> comp = new Comparator<>() {
    @Override
    public int compare(String a, String b) {
        return a.length() - b.length();
    }
};
System.out.println(comp.compare("Hola", "Mundo"));
// Resultado: 0

Ahora (lambda):

Java
Comparator<String> comp = (a, b) -> a.length() - b.length();
System.out.println(comp.compare("Hola", "Java"));
// Resultado: 0 (ambas palabras tienen 4 caracteres)

Piensa en lambdas como “mini funciones” que puedes mover como si fueran datos.


2. Interfaces Funcionales

Son interfaces con un solo método abstracto, lo que las hace compatibles con lambdas.
Java ya trae muchas interfaces funcionales listas para usar:

  • Predicate<T> → recibe un T y devuelve boolean.
Java
Predicate<String> empiezaConA = s -> s.startsWith("A");
System.out.println(empiezaConA.test("Ana"));
// Resultado: true
  • Function<T, R> → recibe un T y devuelve un R.
Java
Function<String, Integer> largo = s -> s.length();
System.out.println(largo.apply("Hola"));
// Resultado: 4
  • Consumer<T> → recibe un T y no devuelve nada.
Java
Consumer<String> imprimir = s -> System.out.println("Hola " + s);
imprimir.accept("Pedro");
// Resultado: Hola Pedro
  • Supplier<T> → no recibe nada, devuelve un T.
Java
Supplier<Double> aleatorio = () -> Math.random();
System.out.println(aleatorio.get());
// Resultado: número aleatorio entre 0.0 y 1.0
  • BiFunction<T,U,R> → recibe dos argumentos y devuelve un valor.
Java
BiFunction<Integer, Integer, Integer> suma = (a,b) -> a + b;
System.out.println(suma.apply(5, 7));
// Resultado: 12

La anotación @FunctionalInterface es opcional, pero sirve para que el compilador te avise si rompes la regla de un solo método abstracto.


3. Stream API

Es una forma de procesar colecciones de datos declarativamente, usando operaciones en cadena.
Un stream es como una cinta transportadora: cada operación transforma o filtra los datos que pasan por ella.

Ejemplo:

Java
List<String> nombres = List.of("Ana", "Pedro", "Alba");

List<String> mayusConA = nombres.stream()
    .filter(n -> n.startsWith("A")) // ["Ana", "Alba"]
    .map(String::toUpperCase)       // ["ANA", "ALBA"]
    .toList();

System.out.println(mayusConA);
// Resultado: [ANA, ALBA]

4. Composición de Funciones

Ejemplo con Function:

Java
Function<Integer, Integer> porDos = x -> x * 2;
Function<Integer, Integer> masTres = x -> x + 3;

Function<Integer, Integer> combinado = porDos.andThen(masTres);
System.out.println(combinado.apply(5));
// Resultado: 13

Ejemplo con Predicate:

Java
Predicate<String> empiezaConA = s -> s.startsWith("A");
Predicate<String> largoMayor3 = s -> s.length() > 3;

Predicate<String> filtro = empiezaConA.and(largoMayor3);

System.out.println(filtro.test("Ana"));     // Resultado: false
System.out.println(filtro.test("Alberto")); // Resultado: true

Ejemplo rápido: Filtrar y transformar datos

Antes:

Java
List<Integer> pares = new ArrayList<>();
for (int num : numeros) {
    if (num % 2 == 0) {
        pares.add(num * 10);
    }
}
System.out.println(pares);
// Resultado (si numeros = [1,2,3,4]): [20, 40]

Ahora:

Java
List<Integer> pares = numeros.stream()
    .filter(n -> n % 2 == 0) // [2, 4]
    .map(n -> n * 10)        // [20, 40]
    .toList();

System.out.println(pares);
// Resultado (si numeros = [1,2,3,4]): [20, 40]

Conclusión

La programación funcional en Java no es un adorno, es una forma distinta de pensar y estructurar el código. Ya viste que con lambdas, interfaces funcionales, Stream API y composición de funciones, podemos escribir menos código, más claro, y con menos errores potenciales.

En este primer paso entendimos qué es el paradigma, cuándo usarlo, y vimos ejemplos que dejan claro cómo pasar de imperativo a funcional.
Ahora viene lo bueno: aprender a manejar el combustible que hace posible todo esto — Lambda Expressions y Method References — para que no solo escribas código más corto, sino más expresivo y modular.


Próximo paso: Post 2 – Lambda Expressions y Method References

En el siguiente capítulo vamos a:

  • Desmenuzar la sintaxis de lambdas y sus variaciones.
  • Entender cuándo usar () y cuándo no.
  • Aprender a referenciar métodos y constructores de forma directa.
  • Combinar lambdas con interfaces funcionales estándar.

Todo con ejemplos reales y prácticos.


Mini aplicación de práctica 💻

Durante esta serie, iremos construyendo una mini aplicación llamada “Tienda Funcional” donde:

  • Tendremos una lista de productos (nombre, precio, categoría).
  • Filtraremos por criterios dinámicos usando Predicate.
  • Transformaremos datos con Function.
  • Mostraremos reportes rápidos con Consumer.
  • Generaremos datos de prueba con Supplier.
  • Usaremos Streams para ordenar, agrupar y resumir información.

Primer objetivo práctico (Post 1 + Post 2):

  1. Crear la clase Producto con sus atributos.
  2. Generar una lista de productos de ejemplo.
  3. Filtrar y transformar esa lista usando lambdas y Stream API.

Esto nos servirá como hilo conductor para que cada nuevo concepto que aprendamos lo implementemos en algo tangible.

Leave a Reply Cancel reply

Your email address will not be published. Required fields are marked *

Comentarios recientes

No comments to show.

Archivos

  • August 2025
  • June 2025

Categorías

  • Blog
©2025 Laboratorios TERA Byte | Powered by SuperbThemes!