orElse(value) nhận một giá trị đã tính sẵn, còn orElseGet(supplier) nhận một hàm chỉ chạy khi Optional rỗng.
Optional<User> cached = Optional.of(user);
cached.orElse(loadFromDb()); // loadFromDb() VẪN chạy dù đã có giá trị
cached.orElseGet(this::loadFromDb); // không chạyJava đánh giá tham số trước khi gọi method, nên orElse luôn tính biểu thức bên trong — nếu đó là truy vấn DB, gọi API, hay tạo object nặng thì bạn trả giá vô ích, và tệ hơn nếu nó có side effect (ghi log, tăng counter, insert row).
Quy tắc: hằng số hoặc giá trị rẻ thì orElse; mọi thứ cần tính toán thì orElseGet.
Các lỗi dùng Optional hay gặp khác:
- opt.get() mà không kiểm tra — không khác gì NPE, chỉ đổi tên exception. Dùng orElseThrow(...) để nói rõ lỗi nghiệp vụ.
- Dùng Optional làm field của entity hoặc tham số method. Optional không Serializable và làm chữ ký rối; nó được thiết kế cho kiểu trả về.
- Optional<List<T>> — trả về list rỗng đơn giản và an toàn hơn.
- Optional.of(x) khi x có thể null (ném NPE ngay) — trường hợp đó phải dùng Optional.ofNullable(x).
- Chuỗi isPresent() + get() thay vì map / filter / ifPresentOrElse.