การแปลง Optionals: map และ flatMap
เชื่อมการแปลงด้วย map และ flatMap เพื่อประมวลผลค่าโดยไม่ต้องตรวจสอบ null
การแปลง Optionals: map และ flatMap เป็นบทเรียน Java Academy ฟรีบน CoddyKit นี่คือบทเรียนที่ 3 จากทั้งหมด 4 บทเรียน คุณสามารถอ่านบทเรียนทั้งหมดด้านล่างฟรี — จากนั้นลองปฏิบัติด้วยตัวคุณเองในเบราว์เซอร์พร้อมตัวแก้ไขโค้ดในตัวและติวเตอร์ AI ตลอด 24/7 บทเรียนนี้เป็นส่วนหนึ่งของเส้นทางการเรียน Java Academy และความก้าวหน้าของคุณจะซิงค์ข้ามเว็บและแอป CoddyKit คอร์ส Java Academy มีบทเรียนทั้งหมด 4 บทเรียน
การแปลง Optional: map และ flatMap
map() จะแปลงค่าภายใน Optional เมื่อมีค่าอยู่ ส่วน flatMap() จะหลีกเลี่ยง Optional ซ้อนกันเมื่อการแปลงนั้นส่งคืน Optional เช่นกัน
map: การแปลงค่า
map(Function) จะใช้ฟังก์ชันกับค่าเมื่อมีค่าอยู่ แล้วห่อหุ้มผลลัพธ์ไว้ใน 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การเชื่อมการเรียก map
การเรียก map หลายครั้งสามารถเชื่อมการแปลงได้อย่างสะอาด โดยไม่ต้องตรวจสอบค่าว่างซ้อนกัน
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: การหลีกเลี่ยง Optional<Optional>
หากฟังก์ชันการแมปของคุณส่งคืน Optional ให้ใช้ flatMap เพื่อคงไว้เป็น Optional แบบแบน แทนที่จะเป็น 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.comflatMap ในการใช้งานจริง: สายโซ่ของที่เก็บข้อมูล
รูปแบบที่พบได้บ่อยคือ การเชื่อมการค้นหาจากที่เก็บข้อมูล โดยแต่ละการค้นหาจะส่งคืน 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.comสรุป map กับ flatMap
การเลือกระหว่าง map และ flatMap:
- ใช้
mapเมื่อฟังก์ชันส่งคืนค่าทั่วไป เช่น String หรือชนิดจำนวนเต็ม - ใช้
flatMapเมื่อฟังก์ชันส่งคืน 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>>)การแยกวิเคราะห์อย่างปลอดภัยด้วย flatMap
รูปแบบที่มีประโยชน์คือ ห่อการดำเนินการที่มีความเสี่ยงและอาจล้มเหลวไว้ใน Optional โดยใช้ 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)); // -1การรวบรวม Optional
กรองและแมปสตรีมของ Optional เพื่อรวบรวมเฉพาะค่าที่มีอยู่
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]การเดินทางผ่านออบเจ็กต์ที่ซ้อนกัน
map และ flatMap ช่วยให้เดินทางผ่านกราฟออบเจ็กต์ที่มีความลึกได้อย่างปลอดภัย โดยไม่ต้องตรวจสอบค่าว่างที่ยุ่งยาก
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 สำหรับการแปลงชนิดข้อมูล
map เหมาะอย่างยิ่งสำหรับการแปลงชนิดของค่าใน Optional เช่น การแยกวิเคราะห์ การจัดรูปแบบ หรือการดึงฟิลด์ย่อย
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)); // 2024การสร้างไปป์ไลน์
การรวม filter, map และ flatMap ช่วยสร้างไปป์ไลน์ข้อมูลที่สื่อความหมายและจัดการกรณีไม่มีค่าในทุกขั้นตอนได้ โดยไม่ต้องตรวจสอบค่าว่างอย่างชัดเจน
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.99ตรวจสอบความเข้าใจ
เมื่อใดควรใช้ flatMap แทน map กับ Optional
สรุป: การแปลง Optional: map และ flatMap
ประเด็นสำคัญ:
- map() จะแปลงค่าเมื่อมีค่าอยู่ และห่อหุ้มผลลัพธ์ไว้ใน Optional
- flatMap() ใช้กับฟังก์ชันที่ส่งคืน Optional เพื่อหลีกเลี่ยง Optional ที่ซ้อนกัน
- เชื่อม map หลายรายการสำหรับการแปลงหลายขั้นตอนโดยไม่ต้องตรวจสอบค่าว่าง
- ใช้ flatMap เพื่อเชื่อมการเรียกที่เก็บข้อมูลหรือบริการซึ่งส่งคืน Optional
- รวม filter + map + flatMap เพื่อสร้างไปป์ไลน์ข้อมูลที่ปลอดภัยจากค่าว่าง
- ใช้ flatMap Optional::stream เพื่อรวม Optional เข้ากับไปป์ไลน์สตรีม
คำถามที่พบบ่อย
บทเรียน “การแปลง Optionals: map และ flatMap” ฟรีหรือไม่
ใช่ — ข้อความเต็มของ “การแปลง Optionals: map และ flatMap” ฟรีให้อ่านที่นี่บนเว็บ เพื่อปฏิบัติแบบโต้ตอบ (ตัวแก้ไขโค้ดในตัวและติวเตอร์ AI ตลอด 24/7) และปลดล็อคส่วนที่เหลือของคอร์ส Java Academy ให้อัปเกรดเป็น CoddyKit PRO คอร์ส Java Academy มีบทเรียนทั้งหมด 4 บทเรียน
คุณจะเรียนรู้อะไรในบทเรียน “การแปลง Optionals: map และ flatMap”
เชื่อมการแปลงด้วย map และ flatMap เพื่อประมวลผลค่าโดยไม่ต้องตรวจสอบ null คุณปฏิบัติ Java Academy ด้วยโค้ดที่ใช้งานได้จริงที่คุณเรียกใช้โดยตรงในเบราว์เซอร์ และติวเตอร์ AI ตลอด 24/7 ตอบคำถามของคุณขณะที่คุณไปผ่านบทเรียน
คุณต้องมีประสบการณ์ก่อนที่จะเริ่มเรียน Java Academy หรือไม่
ไม่จำเป็นต้องมีประสบการณ์มาก่อน Java Academy บน CoddyKit ออกแบบมาสำหรับผู้เริ่มต้นไปจนถึงผู้เรียนขั้นสูง คุณสามารถเริ่มต้นที่นี่หรือเริ่มจากตัวแรกและเรียนด้วยความเร็วของคุณเอง นี่คือบทเรียนที่ 3 จากทั้งหมด 4 บทเรียน
บทเรียน “การแปลง Optionals: map และ flatMap” ใช้เวลานานแค่ไหน
บทเรียน CoddyKit ส่วนใหญ่ใช้เวลาประมาณ 5–10 นาที แต่ละบทเรียนจึงสั้นและเป็นแบบโต้ตอบ คุณสามารถก้าวหน้าอย่างต่อเนื่องและกลับมาเรียนต่อจากตรงที่เพิ่งหยุดบนเว็บและแอปได้เลย
ฉันเขียนและรันโค้ดในบทเรียน Java Academy นี้ได้ไหม
ได้ บทเรียน Java Academy ทุกบทมีตัวแก้ไขโค้ดในตัว คุณจึงเขียนและรันโค้ดจริงได้เลยในเบราว์เซอร์ และได้รับข้อเสนอแนะจาก AI ในทันที — ไม่ต้องติดตั้งในเครื่องของคุณ
บทเรียนทั้งหมดในหลักสูตรนี้
- เหตุผลที่มี Optional
- การสร้างและตรวจสอบ Optionals
- การแปลง Optionals: map และ flatMap
- แนวทางปฏิบัติที่ดีสำหรับ Optional