La programación funcional en Java, introducida con Java 8, transforma la forma de procesar colecciones y datos. Las lambdas y el Streams API reducen el código boilerplate y expresan la intención de forma más clara.
Lambdas
Una lambda es una función anónima. Su sintaxis es (parámetros) -> expresión o (parámetros) -> { bloque; }:
// Lambda simple
Runnable saludo = () -> System.out.println("Hola desde lambda");
saludo.run();
// Lambda con parámetros
Comparator porLongitud = (a, b) -> Integer.compare(a.length(), b.length());
List palabras = new ArrayList<>(List.of("Java", "es", "genial", "y", "moderno"));
palabras.sort(porLongitud);
System.out.println(palabras); // [es, y, Java, genial, moderno]
Interfaces funcionales del JDK
El paquete java.util.function proporciona las interfaces funcionales más comunes:
Interfaz | Método | Uso |
|
| Produce un valor sin entrada |
|
| Consume un valor, no devuelve nada |
|
| Transforma T en R |
|
| Evalúa una condición |
|
| Combina dos valores en uno |
Streams API
Los Streams proporcionan una forma de procesar colecciones de datos de forma declarativa, encadenando operaciones sin modificar la colección original:
Listnombres = List.of("Ana", "Carlos", "Beatriz", "Pedro", "Alicia", "Luis"); // Contar nombres que empiezan por vocal long conVocal = nombres.stream() .filter(n -> "AEIOUaeiou".indexOf(n.charAt(0)) >= 0) .count(); System.out.println("Con vocal inicial: " + conVocal); // 2 // Obtener nombres de más de 4 letras, en mayúsculas, ordenados List resultado = nombres.stream() .filter(n -> n.length() > 4) .map(String::toUpperCase) .sorted() .toList(); System.out.println(resultado); // [ALICIA, BEATRIZ, CARLOS]
Operaciones intermedias y terminales
Las operaciones intermedias devuelven un Stream (lazy, se evalúan solo cuando llega la terminal). Las terminales producen un resultado y consumen el Stream:
Listnumeros = List.of(1, 2, 3, 4, 5, 6, 7, 8, 9, 10); // Suma de los cuadrados de los números pares int suma = numeros.stream() .filter(n -> n % 2 == 0) // intermedia: filtra pares .mapToInt(n -> n * n) // intermedia: eleva al cuadrado .sum(); // terminal: reduce a un int System.out.println(suma); // 220 // Agrupar por longitud Map > porLongitud = nombres.stream() .collect(Collectors.groupingBy(String::length)); // Optional: manejo seguro de valores nulos Optional primero = nombres.stream() .filter(n -> n.startsWith("Z")) .findFirst(); String valor = primero.orElse("No encontrado"); System.out.println(valor); // No encontrado
Streams paralelos
Para procesar grandes colecciones aprovechando múltiples núcleos, basta con cambiar stream() por parallelStream(). El orden de procesamiento no está garantizado:
long cuadradosSuma = LongStream.rangeClosed(1, 1_000_000)
.parallel()
.map(n -> n * n)
.sum();
System.out.println(cuadradosSuma);
