isPresent() + get()Optional<User> u = repo.findById(id);
if (u.isPresent()) {
return u.get().name();
}
return "unknown";if (x != null) x.name() 과 완전히 같은 구조입니다. Optional 객체만 하나 더 만들었을 뿐 null 검사를 잊을 위험이 그대로입니다.
✅
return repo.findById(id).map(User::name).orElse("unknown");orElse 에 비싼 연산User u = cache.find(id).orElse(db.load(id)); // 캐시에 있어도 DB 를 항상 조회!메서드 인자는 호출 전에 평가됩니다(2.5). 캐시 히트율이 99% 여도 DB 부하는 100% 입니다.
✅
User u = cache.find(id).orElseGet(() -> db.load(id));class User {
private Optional<String> nickname; // 직렬화 불가, 필드가 null 일 수도 있음
void setNickname(Optional<String> nick) { ... } // 호출자가 Optional.ofNullable 로 감싸야 함
}✅
class User {
private String nickname; // nullable 필드
Optional<String> nickname() { return Optional.ofNullable(nickname); } // getter 에서만 Optional
void setNickname(String nick) { this.nickname = nick; }
}Optional<List<Order>> findOrders(long userId) {
List<Order> list = query(userId);
return list.isEmpty() ? Optional.empty() : Optional.of(list);
}빈 리스트가 이미 "없음"입니다. 호출자는 orElse(List.of()) 를 붙여야 해서 오히려 불편해집니다.
✅
List<Order> findOrders(long userId) { return query(userId); } // 없으면 빈 리스트Optional.of 에 nullable 값Optional<String> email = Optional.of(user.getEmail()); // getEmail 이 null 이면 NPEof 는 "절대 null 아님" 단언입니다. 외부에서 온 값은 ofNullable.
✅
Optional<String> email = Optional.ofNullable(user.getEmail());get() 무방비 호출Order biggest = orders.stream().max(comparing(Order::amount)).get(); // 빈 스트림이면 NoSuchElementExceptionNoSuchElementException 은 이름만 다른 NPE 입니다.
✅
Order biggest = orders.stream().max(comparing(Order::amount))
.orElseThrow(() -> new IllegalStateException("주문이 없습니다"));Optional<Boolean> isAdmin(User u) // Boolean 은 이미 두 값. 세 번째 상태가 필요한가?
Optional<Integer> count() // 0 이 "없음"이다Optional 은 "값이 존재하지 않을 수 있는 조회" 에만. 항상 값이 있는 계산, 컬렉션, boolean, 카운트에는 쓰지 않습니다.
✅
boolean isAdmin(User u)
int count()