แนวทางปฏิบัติที่ดีสำหรับ Optional
ใช้ orElse, orElseGet, orElseThrow และหลีกเลี่ยงรูปแบบการใช้ Optional ที่ไม่เหมาะสมซึ่งพบบ่อย
แนวทางปฏิบัติที่ดีสำหรับ Optional เป็นบทเรียน Java Academy ฟรีบน CoddyKit นี่คือบทเรียนที่ 4 จากทั้งหมด 4 บทเรียน คุณสามารถอ่านบทเรียนทั้งหมดด้านล่างฟรี — จากนั้นลองปฏิบัติด้วยตัวคุณเองในเบราว์เซอร์พร้อมตัวแก้ไขโค้ดในตัวและติวเตอร์ AI ตลอด 24/7 บทเรียนนี้เป็นส่วนหนึ่งของเส้นทางการเรียน Java Academy และความก้าวหน้าของคุณจะซิงค์ข้ามเว็บและแอป CoddyKit คอร์ส Java Academy มีบทเรียนทั้งหมด 4 บทเรียน
แนวทางปฏิบัติที่ดีสำหรับ Optional
Optional เป็นเครื่องมือที่ทรงพลังเมื่อใช้อย่างถูกต้อง บทเรียนนี้ครอบคลุมสิ่งที่ควรทำและไม่ควรทำ พร้อมตัวอย่างที่เป็นรูปธรรมจากฐานโค้ดในโลกจริง
ควรทำ: ใช้ Optional เป็นชนิดค่าที่ส่งคืน
กรณีใช้งานหลักของ Optional คือใช้เป็นชนิดค่าที่ส่งคืนจากเมธอดซึ่งอาจค้นหาหรือสร้างค่าไม่สำเร็จ
import java.util.Optional;
// Good: signals to caller that result might be absent
public Optional<User> findByUsername(String username) { ... }
public Optional<Config> getConfig(String key) { ... }
public Optional<String> getHeader(String name) { ... }
// These are all cases where absence is a normal outcome,
// not an exceptional conditionไม่ควรทำ: ใช้ Optional เป็นฟิลด์
ฟิลด์ Optional เพิ่มภาระให้กับออบเจ็กต์และทำให้การทำอนุกรมซับซ้อนขึ้น สำหรับฟิลด์ทางเลือกภายในคลาส ให้ใช้ค่าว่างหรือค่าตัวแทน
// BAD
class User {
private Optional<String> middleName; // wrong
}
// GOOD: use null for absent optional field
class User {
private final String middleName; // null = absent
public Optional<String> middleName() {
return Optional.ofNullable(middleName); // expose as Optional in getter
}
}
User u = new User(null); // null field
System.out.println(u.middleName().isPresent()); // falseไม่ควรทำ: ใช้ Optional เป็นพารามิเตอร์ของเมธอด
พารามิเตอร์แบบ Optional บังคับให้ผู้เรียกห่อหุ้มค่าใน Optional โดยไม่จำเป็น ควรใช้การโอเวอร์โหลดหรือ @Nullable แทน
// BAD
void sendNotification(String message, Optional<String> subject) { ... }
// caller must write: sendNotification("Hello", Optional.of("News"))
// GOOD: overloading
void sendNotification(String message) { sendNotification(message, null); }
void sendNotification(String message, String subject) {
// subject may be null
}
// caller writes: sendNotification("Hello", "News") — cleanไม่ควรทำ: ใช้ Optional ในคอลเลกชัน
อย่าใส่ Optional ไว้ภายใน List, ชุด หรือค่าในแมป Optional ว่างในคอลเลกชันไม่มีความหมาย เพียงไม่ต้องใส่รายการนั้น
// BAD: List of Optionals
List<Optional<User>> results = ...; // meaningless empty Optionals
// GOOD: List of present values only
List<User> presentUsers = maybeUsers.stream()
.flatMap(Optional::stream)
.collect(Collectors.toList());
// BAD: Map with Optional values
Map<String, Optional<String>> config = ...;
// GOOD: just use null or omit the key for absent values
Map<String, String> config2 = ...;
String value = config2.getOrDefault("key", "default");ควรทำ: ใช้ orElseGet สำหรับค่าเริ่มต้นที่มีต้นทุนสูง
เมื่อค่าเริ่มต้นต้องผ่านการคำนวณ เช่น การสอบถามฐานข้อมูลหรือการเรียกเครือข่าย ให้ใช้ orElseGet เสมอ เพราะ supplier จะถูกเรียกใช้เมื่อจำเป็นเท่านั้น
import java.util.Optional;
// BAD: buildDefault() always called, even when value is present!
String config = getConfig("timeout").orElse(buildDefault());
// GOOD: supplier called lazily only when empty
String config2 = getConfig("timeout").orElseGet(() -> buildDefault());
// Or with method reference:
String config3 = getConfig("timeout").orElseGet(this::buildDefault);
// For cheap literals, orElse is fine
String name = getConfig("name").orElse("default");ควรทำ: ใช้ orElseThrow สำหรับค่าที่จำเป็น
เมื่อค่าที่หายไปเป็นข้อผิดพลาดในการเขียนโปรแกรมหรือเป็นการละเมิดเงื่อนไขคงที่ ให้ใช้ orElseThrow พร้อมข้อยกเว้นที่อธิบายสาเหตุอย่างชัดเจน
import java.util.Optional;
// Good: throw when absence is an error
User user = userRepository.findById(userId)
.orElseThrow(() -> new UserNotFoundException("User not found: " + userId));
// Good: in validation code
String apiKey = Optional.ofNullable(System.getenv("API_KEY"))
.orElseThrow(() -> new IllegalStateException(
"API_KEY environment variable is required"));
System.out.println("Key found: " + apiKey.length() + " chars");รูปแบบต่อต้าน: isPresent + get()
ควรหลีกเลี่ยงรูปแบบต่อต้านที่ตรวจสอบ isPresent() แล้วจึงเรียก get() วิธีนี้ไม่ได้ดีกว่าการตรวจสอบค่าว่าง และทำให้จุดประสงค์ของ Optional สูญเสียไป
import java.util.Optional;
Optional<String> opt = findValue();
// BAD: isPresent() + get() — no improvement over null check
if (opt.isPresent()) {
String val = opt.get();
process(val);
}
// GOOD: use the functional API
opt.ifPresent(this::process);
// GOOD: transform and return
return opt.map(this::process).orElse(null);
// GOOD: provide a default
String result = opt.orElse("default");แนวทางปฏิบัติที่ดีในการเชื่อมการทำงาน
สร้างสายโซ่ที่สะอาด: ค้นหา → filter → แปลงข้อมูล → fallback แต่ละขั้นจะอธิบายตัวเองได้
import java.util.Optional;
record User(long id, String plan, boolean active) {}
static Optional<User> findUser(long id) { return Optional.empty(); }
String result = findUser(42L)
.filter(User::active) // keep only active users
.filter(u -> "PRO".equals(u.plan())) // keep only PRO users
.map(u -> "Welcome, Pro user #" + u.id()) // transform
.orElse("Upgrade to Pro!"); // fallback
System.out.println(result); // Upgrade to Pro!Optional ในชั้นบริการ
ตัวอย่างชั้นบริการที่ใกล้เคียงกับการใช้งานจริงและปฏิบัติตามแนวทางที่ดี
import java.util.Optional;
class OrderService {
public Optional<OrderSummary> getOrderSummary(long orderId) {
return orderRepo.findById(orderId)
.filter(o -> !o.isCancelled())
.map(this::toSummary);
}
public OrderSummary requireOrderSummary(long orderId) {
return getOrderSummary(orderId)
.orElseThrow(() -> new OrderNotFoundException(orderId));
}
private OrderSummary toSummary(Order o) { return new OrderSummary(o); }
}
// API callers choose: Optional (handle absence) or require (exception)Optional กับเครื่องมือเพื่อความปลอดภัยจากค่าว่าง
Optional ทำงานเสริมกับคำอธิบายประกอบ @Nullable/@NonNull และเครื่องมืออย่าง SpotBugs/NullAway เพื่อให้ครอบคลุมความปลอดภัยจากค่าว่างอย่างสมบูรณ์
// Annotation-based: declares intent for in-class nulls
import org.jetbrains.annotations.*;
class ProductService {
@Nullable // may return null — for framework/bean use
public String getCachedName(String id) { return cache.get(id); }
// Optional — for service API that handles absence
public Optional<Product> findProduct(String id) {
return repo.findById(id);
}
}
// Use @Nullable for fields/parameters; Optional for return typesตรวจสอบความเข้าใจ
โค้ดต่อไปนี้มีปัญหาอย่างไร
if (opt.isPresent()) {
process(opt.get());
}สรุป: แนวทางปฏิบัติที่ดีสำหรับ Optional
ประเด็นสำคัญ:
- ใช้ Optional เฉพาะเป็นชนิดค่าที่ส่งคืนเท่านั้น อย่าใช้เป็นฟิลด์หรือพารามิเตอร์ของเมธอด
- เลือกใช้ orElseGet แทน orElse เมื่อค่าเริ่มต้นมีต้นทุนสูงในการคำนวณ
- ใช้ orElseThrow เมื่อการไม่มีค่าแสดงถึงข้อผิดพลาดในการเขียนโปรแกรม
- หลีกเลี่ยง isPresent() + get() ให้ใช้ ifPresent, map หรือ orElse แทน
- อย่าใส่ Optional ไว้ในคอลเลกชัน ให้กรองสตรีมแทน
- สร้างสายโซ่ที่อ่านง่าย: filter → map → orElse เพื่อให้การไหลของข้อมูลชัดเจน
คำถามที่พบบ่อย
บทเรียน “แนวทางปฏิบัติที่ดีสำหรับ Optional” ฟรีหรือไม่
ใช่ — ข้อความเต็มของ “แนวทางปฏิบัติที่ดีสำหรับ Optional” ฟรีให้อ่านที่นี่บนเว็บ เพื่อปฏิบัติแบบโต้ตอบ (ตัวแก้ไขโค้ดในตัวและติวเตอร์ AI ตลอด 24/7) และปลดล็อคส่วนที่เหลือของคอร์ส Java Academy ให้อัปเกรดเป็น CoddyKit PRO คอร์ส Java Academy มีบทเรียนทั้งหมด 4 บทเรียน
คุณจะเรียนรู้อะไรในบทเรียน “แนวทางปฏิบัติที่ดีสำหรับ Optional”
ใช้ orElse, orElseGet, orElseThrow และหลีกเลี่ยงรูปแบบการใช้ Optional ที่ไม่เหมาะสมซึ่งพบบ่อย คุณปฏิบัติ Java Academy ด้วยโค้ดที่ใช้งานได้จริงที่คุณเรียกใช้โดยตรงในเบราว์เซอร์ และติวเตอร์ AI ตลอด 24/7 ตอบคำถามของคุณขณะที่คุณไปผ่านบทเรียน
คุณต้องมีประสบการณ์ก่อนที่จะเริ่มเรียน Java Academy หรือไม่
ไม่จำเป็นต้องมีประสบการณ์มาก่อน Java Academy บน CoddyKit ออกแบบมาสำหรับผู้เริ่มต้นไปจนถึงผู้เรียนขั้นสูง คุณสามารถเริ่มต้นที่นี่หรือเริ่มจากตัวแรกและเรียนด้วยความเร็วของคุณเอง นี่คือบทเรียนที่ 4 จากทั้งหมด 4 บทเรียน
บทเรียน “แนวทางปฏิบัติที่ดีสำหรับ Optional” ใช้เวลานานแค่ไหน
บทเรียน CoddyKit ส่วนใหญ่ใช้เวลาประมาณ 5–10 นาที แต่ละบทเรียนจึงสั้นและเป็นแบบโต้ตอบ คุณสามารถก้าวหน้าอย่างต่อเนื่องและกลับมาเรียนต่อจากตรงที่เพิ่งหยุดบนเว็บและแอปได้เลย
ฉันเขียนและรันโค้ดในบทเรียน Java Academy นี้ได้ไหม
ได้ บทเรียน Java Academy ทุกบทมีตัวแก้ไขโค้ดในตัว คุณจึงเขียนและรันโค้ดจริงได้เลยในเบราว์เซอร์ และได้รับข้อเสนอแนะจาก AI ในทันที — ไม่ต้องติดตั้งในเครื่องของคุณ
บทเรียนทั้งหมดในหลักสูตรนี้
- เหตุผลที่มี Optional
- การสร้างและตรวจสอบ Optionals
- การแปลง Optionals: map และ flatMap
- แนวทางปฏิบัติที่ดีสำหรับ Optional