นากกายสีมิ้นต์กำลังเปิดกล่องสำรองเฉพาะเมื่อกล่องหลักว่างบนโต๊ะสว่าง

Java Optional: orElse สร้างค่าทิ้งได้ ส่วน orElseGet ทำเมื่อจำเป็น

พี่โชว์Engineering

optional.orElse(makeDefault()) อ่านเหมือนสร้างค่าเมื่อว่าง แต่ Java ประเมิน argument ก่อนเรียกเมธอดครับ makeDefault() จึงทำงานแม้ Optional มีค่า ถ้าฟังก์ชันนั้นอ่านฐานข้อมูล, สร้าง object ใหญ่ หรือเพิ่ม metric เราจ่ายต้นทุนและ side effect โดยไม่ใช้ผลลัพธ์

WHY: argument ของเมธอดเป็น eager

กติกาไม่ได้พิเศษสำหรับ Optional: Java ต้องคำนวณ argument ก่อนส่งเข้า orElse ส่วน orElseGet รับ Supplier จึงค่อยเรียกเมื่อไม่มีค่า เอกสาร Optional แยก contract สองแบบนี้ชัด

import java.util.Optional;
import java.util.concurrent.atomic.AtomicInteger;

public class Main {
    static String fallback(AtomicInteger calls) {
        calls.incrementAndGet();
        return "generated";
    }

    public static void main(String[] args) {
        AtomicInteger eagerCalls = new AtomicInteger();
        String present = Optional.of("saved").orElse(fallback(eagerCalls));
        assert present.equals("saved");
        assert eagerCalls.get() == 1;

        AtomicInteger lazyCalls = new AtomicInteger();
        String lazyPresent = Optional.of("saved").orElseGet(() -> fallback(lazyCalls));
        assert lazyPresent.equals("saved");
        assert lazyCalls.get() == 0;

        String missing = Optional.<String>empty().orElseGet(() -> fallback(lazyCalls));
        assert missing.equals("generated");
        assert lazyCalls.get() == 1;
    }
}

เลือกจาก contract ไม่ใช่จำว่า Get เร็วกว่า

ถ้าค่า fallback เป็น literal หรือ object ที่สร้างไว้แล้ว orElse ชัดและไม่เสียอะไร หากต้องคำนวณหรือมี side effect ใช้ orElseGet แต่ supplier ควรสั้นและคาดเดาได้ การซ่อน network call ไว้ใน chain ยาวทำให้ timeout, tracing และ error handling มองยาก

เมื่อ “ไม่มีค่า” เป็นข้อผิดพลาด ใช้ orElseThrow พร้อม exception ที่อธิบาย context อย่าสร้าง default เพื่อกลบข้อมูลหาย และอย่าใช้ Optional เป็น field/parameter ทุกจุดเพียงเพื่อลบ null; API นี้เหมาะกับ return value ที่อาจไม่มีผลลัพธ์มากที่สุด

Recap

  • orElse(value) ประเมิน value เสมอ
  • orElseGet(supplier) เรียก supplier เฉพาะตอนว่าง
  • literal ง่ายใช้ orElse; งานแพงใช้ orElseGet
  • absence ที่ผิดกติกาควร orElseThrow ไม่ใช่กลบด้วยค่า default