1️⃣ Optional 문법
Optional.of(value) 절대 null이 아니어야 함
Optional.ofNullable(value) null일 수도 있음
Optional.empty() 빈 Optional 생성
get() 값 꺼냄 (값이 없으면 예외 발생)
orElse(default) 값이 없으면 기본값 리턴
orElseGet(Supplier) 값이 없으면 람다 결과 리턴
orElseThrow() 값이 없으면 예외 발생
isPresent() 값이 있는지 확인
ifPresent(Consumer) 값이 있으면 처리
filter(Predicate) 조건에 맞는 값만 유지
2️⃣개념 요약
Optional<T>
은 null로 인한 예외를 방지하고, 명시적으로 값 유무를 처리할 수 있는 컨테이너 클래스
- 흔히
null
체크에 사용되던 코드를 더 명확하고 선언적으로 바꾸어줌
- 비유하자면, "선물 상자에 값이 들어있을 수도, 없을 수도 있다"
테스트 예제
public class OptionalTest {
@Test
public void t1() {
String name = "metacoding";
Optional<String> opt = Optional.of(name);
System.out.println(opt.get()); // metacoding 출력
}
@Test
public void t1_null() {
String name = null;
Optional<String> opt = Optional.ofNullable(name);
if (opt.isPresent()) {
System.out.println(opt.get());
} else {
System.out.println("선물박스에 값이 없어요");
}
}
@Test
public void t2() {
String name = null;
Optional<String> opt = Optional.ofNullable(name);
String result = opt.orElseThrow(() -> new RuntimeException("값이 없어요"));
System.out.println(result);
}
@Test
public void t3() {
String name = null;
Optional<String> opt = Optional.ofNullable(name);
String result = opt.orElseGet(() -> "metacoding"); // 기본값 리턴
System.out.println(result); // metacoding
}
}
💡 Optional.of()는 null을 허용하지 않음.💡Optional.ofNullable()
은 null 허용 (값 없으면 empty).💡orElseThrow()
는 값 없을 때 예외 발생.💡orElseGet()
은 값 없을 때 기본값 제공.
3️⃣기존 코드 vs Optional 적용
- null 체크 수동 처리
public User findById(Integer id) {
User user = em.find(User.class, id);
if (user == null) {
return null;
} else {
return user;
}
}
- Optional 적용
public Optional<User> findById(Integer id) {
return Optional.ofNullable(em.find(User.class, id));
}
4️⃣서비스 계층 적용 예시
- 적용 전
User userPS = userRepository.findById(userId);
if (userPS == null) throw new Exception404("자원을 찾을 수 없습니다");
userPS.update(updateDTO.getPassword(), updateDTO.getEmail());
- 적용 후
User userPS = userRepository.findById(userId)
.orElseThrow(() -> new Exception404("자원을 찾을 수 없습니다."));
userPS.update(updateDTO.getPassword(), updateDTO.getEmail());
5️⃣UserJoin
- Before
User user = userRepository.findByUsername(loginDTO.getUsername());
if (user == null) throw new Exception401("유저네임 혹은 비밀번호가 틀렸습니다");
- After
User userPS = userRepository.findByUsername(loginDTO.getUsername())
.orElseThrow(() -> new Exception401("유저네임 혹은 비밀번호가 틀렸습니다"));
6️⃣유저네임 중복 체크
- Before
User user = userRepository.findByUsername(username);
Map<String, Object> dto = new HashMap<>();
if (user == null) {
dto.put("available", true);
} else {
dto.put("available", false);
}
- After
Optional<User> userOP = userRepository.findByUsername(username);
Map<String, Object> dto = new HashMap<>();
if (userOP.isPresent()) {
dto.put("available", false);
} else {
dto.put("available", true);
}
return dto;
}
7️⃣요약
메서드 | 설명 |
Optional.of() | null 허용 ❌ (NPE 발생) |
Optional.ofNullable() | null 허용 ⭕ |
isPresent() | 값 존재 여부 확인 |
orElse() | 기본값 제공 |
orElseGet() | 람다식으로 기본값 제공 |
orElseThrow() | 예외 발생 |
Share article