Przekształcanie obiektów Optional: map i flatMap
Łącz przekształcenia za pomocą map i flatMap, aby przetwarzać wartości bez sprawdzania null.
Przekształcanie obiektów Optional: map i flatMap to bezpłatna lekcja Java Academy na CoddyKit. To lekcja 3 z 4. Możesz przeczytać całą lekcję poniżej za darmo — a potem ćwiczyć ją interaktywnie w przeglądarce z wbudowanym edytorem kodu i tutorem AI dostępnym 24/7. To część ścieżki edukacyjnej Java Academy, a Twój postęp synchronizuje się między webem a aplikacją CoddyKit. Kurs Java Academy zawiera 4 lekcji w sumie.
Przekształcanie Optional: map i flatMap
map() przekształca wartość wewnątrz Optional, jeśli jest ona obecna. flatMap() zapobiega zagnieżdżaniu Optional, gdy samo przekształcenie zwraca Optional.
map: przekształcanie wartości
map(Function) stosuje funkcję do wartości, jeśli jest ona obecna, i opakowuje wynik w nowy Optional. Jeśli pierwotny Optional był pusty, metoda zwraca pusty Optional.
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()); // falseŁączenie wywołań map
Wiele wywołań map pozwala przejrzyście łączyć przekształcenia bez zagnieżdżonych sprawdzeń null.
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: unikanie Optional<Optional>
Jeśli funkcja mapująca zwraca Optional, należy użyć flatMap, aby zachować płaski Optional zamiast zagnieżdżonego Optional<Optional>.
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.comRzeczywiste użycie flatMap: łańcuch repozytoriów
Częsty wzorzec: łączenie wywołań repozytoriów, z których każde zwraca 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.comPodsumowanie map i flatMap
Wybór między map a flatMap:
- Należy używać
map, gdy funkcja zwraca zwykłą wartość (String, Integer) - Należy używać
flatMap, gdy funkcja zwraca 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>>)Bezpieczne parsowanie za pomocą flatMap
Przydatny wzorzec: opakowanie w Optional operacji, które mogą zakończyć się błędem, za pomocą 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)); // -1Zbieranie wartości Optional
Funkcje filter i map zastosowane do strumienia Optional pozwalają zebrać tylko obecne wartości.
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]Przechodzenie przez zagnieżdżone obiekty
map i flatMap umożliwiają bezpieczne przechodzenie przez głębokie grafy obiektów bez żmudnych sprawdzeń 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 do konwersji typów
map świetnie nadaje się do konwertowania typów wartości Optional — na przykład podczas parsowania, formatowania lub wyodrębniania pola podrzędnego.
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)); // 2024Budowanie potoków
Połączenie filter, map i flatMap pozwala budować wyraziste potoki danych, które obsługują brak wartości na każdym etapie bez jawnych sprawdzeń 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.99Szybkie sprawdzenie
Kiedy należy użyć flatMap zamiast map dla Optional?
Podsumowanie: przekształcanie Optional: map i flatMap
Najważniejsze informacje:
- map() przekształca obecną wartość, opakowując wynik w Optional
- flatMap() służy do funkcji zwracających Optional i zapobiega zagnieżdżaniu Optional
- Wiele wywołań map można łączyć w wieloetapowe przekształcenia bez sprawdzeń null
- flatMap należy stosować do łączenia wywołań repozytoriów i usług zwracających Optional
- Połączenie filter + map + flatMap pozwala budować bezpieczne względem null potoki danych
- flatMap Optional::stream pozwala włączać Optional do potoków strumieni
Często zadawane pytania
Czy lekcja „Przekształcanie obiektów Optional: map i flatMap” jest bezpłatna?
Tak — pełny tekst „Przekształcanie obiektów Optional: map i flatMap” jest dostępny za darmo tutaj w sieci. Aby ćwiczyć ją interaktywnie (wbudowany edytor kodu i tutor AI dostępny 24/7) i odblokować resztę kursu Java Academy, przejdź na CoddyKit PRO. Kurs Java Academy zawiera 4 lekcji w sumie.
Co nauczysz się w „Przekształcanie obiektów Optional: map i flatMap”?
Łącz przekształcenia za pomocą map i flatMap, aby przetwarzać wartości bez sprawdzania null. Ćwiczysz Java Academy z praktycznym kodem, który uruchamiasz bezpośrednio w przeglądarce, a tutor AI dostępny 24/7 odpowiada na Twoje pytania podczas pracy nad lekcją.
Czy potrzebuję doświadczenia, aby zacząć Java Academy?
Nie wymagamy żadnego doświadczenia. Java Academy w CoddyKit jest strukturyzowany dla początkujących i zaawansowanych użytkowników, więc możesz zacząć tutaj lub od początku i uczyć się w swoim tempie. To lekcja 3 z 4.
Ile czasu zajmuje lekcja „Przekształcanie obiektów Optional: map i flatMap”?
Większość lekcji CoddyKit trwa około 5–10 minut. Każda lekcja to mały, interaktywny krok, dzięki czemu robisz systematyczne postępy i zawsze wracasz dokładnie do tego samego miejsca — na webie i w aplikacji.
Czy mogę pisać i uruchamiać kod w tej lekcji Java Academy?
Tak. Każda lekcja Java Academy zawiera wbudowany edytor kodu, więc piszesz i uruchamiasz prawdziwy kod bezpośrednio w przeglądarce i od razu otrzymujesz sprzężenie zwrotne od AI — bez konfiguracji na komputerze.
Wszystkie lekcje w tym kursie
- Dlaczego istnieje Optional
- Tworzenie i sprawdzanie obiektów Optional
- Przekształcanie obiektów Optional: map i flatMap
- Dobre praktyki używania Optional