0Pricing
Java Academy · บทเรียน

แนวทางปฏิบัติที่ดีสำหรับ 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 ในทันที — ไม่ต้องติดตั้งในเครื่องของคุณ

บทเรียนทั้งหมดในหลักสูตรนี้

  1. เหตุผลที่มี Optional
  2. การสร้างและตรวจสอบ Optionals
  3. การแปลง Optionals: map และ flatMap
  4. แนวทางปฏิบัติที่ดีสำหรับ Optional
← กลับไปที่ Java Academy