Java Optional: orElse สร้างค่าทิ้งได้ ส่วน orElseGet ทำเมื่อจำเป็น
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