Programación funcional en Java: técnicas avanzadas y Stream API

Entrenador de Python en Línea para Principiantes

Aprende Python fácilmente sin sobrecargarte de teoría. Resuelve tareas prácticas con verificación automática, recibe pistas y escribe código directamente en el navegador, sin instalar nada.

Start Course

Programación funcional en Java: nivel avanzado



La programación funcional (PF) es un paradigma en el que los cálculos se consideran como la evaluación de funciones matemáticas, evitando cambios de estado y datos mutables. Java, siendo un lenguaje orientado a objetos, recibió con Java 8 potentes herramientas para PF: expresiones lambda, Stream API e interfaces funcionales. A nivel avanzado, estas capacidades permiten escribir código más conciso, seguro y expresivo, especialmente al trabajar con colecciones, operaciones asíncronas y manejo de errores.



En este artículo exploraremos técnicas avanzadas de programación funcional en Java: composición de funciones, mónadas (Optional y CompletableFuture), Stream API con procesamiento paralelo y currying.



1. Composición de funciones e interfaces funcionales



En Java, las interfaces funcionales son interfaces con un único método abstracto (SAM). Las más utilizadas son: Function<T, R>, Predicate<T>, Consumer<T> y Supplier<T>. El uso avanzado incluye la composición de funciones mediante los métodos andThen() y compose().



Ejemplo: cadena de transformaciones



import java.util.function.Function;

public class FunctionComposition { public static void main(String[] args) { // Función: string -> su longitud Function<String, Integer> lengthFunction = String::length; // Función: número -> su cuadrado Function<Integer, Integer> squareFunction = x -> x * x;

// Composición: string -> longitud -> cuadrado de la longitud Function<String, Integer> composedFunction = lengthFunction.andThen(squareFunction);

String text = "Hello, Java!"; int result = composedFunction.apply(text); // 12 * 12 = 144 System.out.println("Resultado: " + result); // 144 }}


El método andThen() aplica primero la primera función y luego la segunda. compose() hace lo contrario: primero aplica la función pasada y luego la primera. Esto permite construir cadenas de transformaciones flexibles y reutilizables.



Ejemplo práctico: filtrado y transformación de una lista



import java.util.List;import java.util.function.Function;import java.util.function.Predicate;import java.util.stream.Collectors;

public class PredicateAndFunction { public static void main(String[] args) { List<String> names = List.of("Alice", "Bob", "Charlie", "David", "Eve");

Predicate<String> startsWithA = s -> s.startsWith("A"); Function<String, String> toUpperCase = String::toUpperCase;

List<String> result = names.stream() .filter(startsWithA) .map(toUpperCase) .collect(Collectors.toList());

System.out.println(result); // [ALICE] }}


2. Mónadas en Java: Optional y CompletableFuture



Una mónada es un patrón que encapsula un valor y proporciona operaciones para transformarlo sin desempaquetarlo explícitamente. En Java, las mónadas se implementan a través de Optional (para manejar null) y CompletableFuture (para operaciones asíncronas).



Optional como mónada

Los métodos map(), flatMap() y filter() permiten trabajar en cadena con la posible ausencia de un valor.



import java.util.Optional;

public class OptionalMonad { public static void main(String[] args) { // Creamos un Optional con un valor no vacío Optional<String> optional = Optional.of("Hello");

// Cadena de transformaciones String result = optional .filter(s -> s.length() > 3) // filtro .m

Blogs

Book Recommendations