Transformación de Optionals: map y flatMap
Encadene transformaciones con map y flatMap para procesar valores sin comprobaciones de null.
Transformación de Optionals: map y flatMap es una lección gratuita de Java Academy en CoddyKit. Esta es la lección 3 de 4. Puedes leer la lección completa abajo gratuitamente — luego la practicas en el navegador con un editor de código integrado y un tutor de IA 24/7. Forma parte de la ruta de aprendizaje de Java Academy, y tu progreso se sincroniza en la web y la app de CoddyKit. El curso de Java Academy incluye 4 lecciones en total.
Transformar Optionals: map y flatMap
map() transforma el valor dentro de un Optional si está presente. flatMap() evita los Optionals anidados cuando la propia transformación devuelve un Optional.
map: transformar el valor
map(Function) aplica la función al valor si está presente y envuelve el resultado en un nuevo Optional. Devuelve un valor vacío si originalmente estaba vacío.
import java.util.Optional;
Optional<String> name = Optional.of("alice");
Optional<String> upper = name.map(String::toUpperCase);
System.out.println(upper.get()); // ALICE
Optional<Integer> length = name.map(String::length);
System.out.println(length.get()); // 5
// Empty in → empty out
Optional<String> empty = Optional.<String>empty().map(String::toUpperCase);
System.out.println(empty.isPresent()); // falseEncadenar llamadas a map
Varias llamadas a map encadenan las transformaciones de forma clara, sin comprobaciones de null anidadas.
import java.util.Optional;
record Address(String city, String country) {}
record User(String name, Address address) {}
User user = new User("Alice", new Address("New York", "US"));
// Chain of maps — safe even if any step returns null
Optional<String> city = Optional.ofNullable(user)
.map(User::address)
.map(Address::city)
.map(String::toUpperCase);
System.out.println(city.orElse("Unknown")); // NEW YORKflatMap: evitar Optional<Optional>
Si su función de mapeo devuelve Optional, use flatMap para mantener un Optional plano en lugar de un Optional<Optional> anidado.
import java.util.Optional;
record User(String name, Optional<String> email) {}
User u = new User("Bob", Optional.of("bob@example.com"));
// map returns Optional<Optional<String>> — ugly!
Optional<Optional<String>> nested = Optional.of(u).map(User::email);
// flatMap flattens: Optional<String>
Optional<String> flat = Optional.of(u).flatMap(User::email);
System.out.println(flat.get()); // bob@example.comflatMap en la práctica: cadena de repositorios
Un patrón habitual: encadenar búsquedas en repositorios donde cada una devuelve Optional.
import java.util.Optional;
record Order(long id, long userId, double total) {}
record User(long id, String name, String email) {}
static Optional<Order> findOrder(long orderId) {
return orderId == 1 ? Optional.of(new Order(1, 42, 99.99)) : Optional.empty();
}
static Optional<User> findUser(long userId) {
return userId == 42 ? Optional.of(new User(42, "Alice", "a@co.com")) : Optional.empty();
}
Optional<String> email = findOrder(1)
.flatMap(o -> findUser(o.userId()))
.map(User::email);
System.out.println(email.orElse("Not found")); // a@co.comResumen de map frente a flatMap
Cómo elegir entre map y flatMap:
- Use
mapcuando la función devuelva un valor simple (String, Integer) - Use
flatMapcuando la función devuelva un Optional
import java.util.Optional;
// map: T → R
Optional.of("hello").map(String::toUpperCase); // Optional<String>
Optional.of("42").map(Integer::parseInt); // Optional<Integer>
// flatMap: T → Optional<R>
Optional.of("42").flatMap(s -> {
try { return Optional.of(Integer.parseInt(s)); }
catch (NumberFormatException e) { return Optional.empty(); }
}); // Optional<Integer> (not Optional<Optional<Integer>>)Análisis seguro con flatMap
Un patrón práctico: envolver en Optional las operaciones arriesgadas que podrían fallar mediante flatMap.
import java.util.Optional;
static Optional<Integer> tryParseInt(String s) {
try { return Optional.of(Integer.parseInt(s)); }
catch (NumberFormatException e) { return Optional.empty(); }
}
Optional<String> input = Optional.of("123");
Optional<Integer> parsed = input.flatMap(JavaOptional::tryParseInt);
System.out.println(parsed.map(n -> n * 2).orElse(-1)); // 246
Optional<String> bad = Optional.of("abc");
Optional<Integer> failed = bad.flatMap(JavaOptional::tryParseInt);
System.out.println(failed.orElse(-1)); // -1Recopilar Optionals
Filtre y transforme un stream de Optionals para recopilar únicamente los valores presentes.
import java.util.*;
import java.util.stream.*;
List<String> inputs = List.of("10", "abc", "25", "nope", "7");
List<Integer> numbers = inputs.stream()
.flatMap(s -> {
try { return Stream.of(Integer.parseInt(s)); }
catch (NumberFormatException e) { return Stream.empty(); }
})
.collect(Collectors.toList());
System.out.println(numbers); // [10, 25, 7]Recorrer objetos anidados
map y flatMap permiten recorrer de forma segura grafos de objetos profundos sin tediosas comprobaciones de null.
import java.util.Optional;
record Company(String name, Optional<Address> address) {}
record Address(String city, Optional<String> zipCode) {}
Company company = new Company(
"Acme Corp",
Optional.of(new Address("Austin", Optional.of("78701")))
);
String zip = Optional.of(company)
.flatMap(Company::address)
.flatMap(Address::zipCode)
.orElse("N/A");
System.out.println(zip); // 78701map para conversiones de tipo
map es excelente para convertir el tipo de los valores de Optional, por ejemplo, al analizar, dar formato o extraer un subcampo.
import java.util.Optional;
import java.time.LocalDate;
// Parse a date from String safely
static Optional<LocalDate> parseDate(String s) {
try { return Optional.of(LocalDate.parse(s)); }
catch (Exception e) { return Optional.empty(); }
}
Optional<String> dateStr = Optional.of("2024-06-15");
Optional<Integer> year = dateStr
.flatMap(JavaOptional::parseDate)
.map(LocalDate::getYear);
System.out.println(year.orElse(-1)); // 2024Construir pipelines
Combinar filter, map y flatMap permite construir pipelines de datos expresivos que gestionan la ausencia en cada paso sin comprobaciones explícitas de null.
import java.util.Optional;
record Product(String sku, String category, boolean inStock, double price) {}
static Optional<Product> findProduct(String sku) {
if ("LAPTOP-1".equals(sku))
return Optional.of(new Product("LAPTOP-1", "Electronics", true, 999.99));
return Optional.empty();
}
Optional<String> priceTag = findProduct("LAPTOP-1")
.filter(Product::inStock)
.filter(p -> p.price() < 2000)
.map(p -> String.format("%s: $%.2f", p.sku(), p.price()));
System.out.println(priceTag.orElse("Not available")); // LAPTOP-1: $999.99Comprobación rápida
¿Cuándo debería usar flatMap en lugar de map en un Optional?
Resumen: transformar Optionals: map y flatMap
Conclusiones principales:
- map() transforma el valor si está presente y envuelve el resultado en un Optional
- flatMap() es para funciones que devuelven Optional; evita los Optionals anidados
- Encadene varios map para realizar transformaciones de varios pasos sin comprobaciones de null
- Use flatMap para encadenar llamadas a repositorios o servicios que devuelven Optional
- Combine filter + map + flatMap para construir pipelines de datos seguros frente a null
- Use flatMap Optional::stream para incorporar Optionals a los pipelines de streams
Preguntas frecuentes
¿La lección «Transformación de Optionals: map y flatMap» es gratis?
Sí — el texto completo de «Transformación de Optionals: map y flatMap» es gratis para leer aquí en la web. Para practicarla de forma interactiva (editor de código integrado y tutor de IA 24/7) y desbloquear el resto del curso de Java Academy, actualiza a CoddyKit PRO. El curso de Java Academy incluye 4 lecciones en total.
¿Qué aprenderé en «Transformación de Optionals: map y flatMap»?
Encadene transformaciones con map y flatMap para procesar valores sin comprobaciones de null. Practicas Java Academy con código real que ejecutas directamente en el navegador, y un tutor de IA 24/7 responde tus preguntas mientras trabajas en la lección.
¿Necesito experiencia previa para empezar Java Academy?
No se requiere experiencia previa. Java Academy en CoddyKit está estructurado para principiantes hasta estudiantes avanzados, así que puedes empezar aquí o desde el inicio y avanzar a tu ritmo. Esta es la lección 3 de 4.
¿Cuánto tiempo toma la lección «Transformación de Optionals: map y flatMap»?
La mayoría de las lecciones de CoddyKit toman alrededor de 5–10 minutos. Cada una es compacta e interactiva, así que avanzas constantemente y retomas exactamente por donde dejaste en la web y la app.
¿Puedo escribir y ejecutar código en esta lección de Java Academy?
Sí. Cada lección de Java Academy incluye un editor de código integrado, así que escribes y ejecutas código real directamente en tu navegador y obtienes retroalimentación instantánea de IA — sin configuración local necesaria.
Todas las lecciones de este curso
- Por qué existe Optional
- Creación e inspección de Optionals
- Transformación de Optionals: map y flatMap
- Buenas prácticas con Optional