1. 왜 사용하는가?
- NullPointerException(NPE) 방지: 값이 null일 때 발생하는 치명적인 오류를 막아줍니다.
- 명시적인 표현: 반환 타입이 Optional<Member>라면, "이 결과는 값이 없을 수도 있으니 반드시 체크해라"라는 강력한 메시지를 개발자에게 전달합니다.
2. 주요 사용 패턴 (1개 조회 시)
보통 결과가 0개 또는 1개인 조회 메서드(findById, findByName)에서 주로 사용합니다.
- 값이 있을 때만 실행: ifPresent()를 사용하여 값이 존재할 때만 특정 로직(예: 중복 체크)을 수행합니다.
- 값이 없으면 예외 발생: orElseThrow()를 사용하여 값이 없을 경우 커스텀 에러를 던집니다.
- 값이 없으면 기본값 반환: orElse()를 사용하여 빈 상자일 때 대신 내보낼 값을 지정합니다.
3. 왜 findAll에는 안 쓰는가?
- 리스트 자체가 비어있음: List<Member>는 데이터가 없으면 null이 아니라 **빈 리스트([])**를 반환하는 것이 관례입니다.
- 불필요한 중복: 리스트 자체가 이미 "데이터가 없음"을 표현할 수 있으므로, 굳이 Optional로 또 감쌀 필요가 없어 사용하지 않습니다.
4. 테스트 코드에서의 주의점
- 상자 열기: Optional은 '상자'와 같아서 안에 든 알맹이(Member)와 직접 비교할 수 없습니다.
- .get() 사용: 테스트 검증 시에는 .get() 메서드를 호출하여 상자 안의 실제 객체를 꺼낸 뒤 비교해야 합니다.
1. 단건 조회: Optional 사용
결과가 없거나 하나일 때는 Optional로 감싸서 반환합니다.
// 특정 ID로 회원 찾기 (0개 또는 1개)
public Optional<Member> findById(Long id) {
// store.get(id) 결과가 null이어도 Optional 상자에 담아서 반환하므로 안전합니다.
return Optional.ofNullable(store.get(id));
}
// 특정 이름으로 회원 찾기 (0개 또는 1개)
public Optional<Member> findByName(String name) {
return store.values().stream()
.filter(member -> member.getName().equals(name))
.findAny(); // 찾은 즉시 Optional로 감싸서 반환, 없으면 빈 Optional 반환
}
2. 전체 조회: List 사용
결과가 여러 개이거나 아예 없을 수 있는 목록 조회는 Optional을 쓰지 않고 빈 리스트를 반환합니다.
// 모든 회원 목록 가져오기
public List<Member> findAll() {
// 데이터가 하나도 없어도 null이 아니라 빈 리스트([])를 반환합니다.
return new ArrayList<>(store.values());
}
3. 테스트 코드에서 비교하는 법 (차이점)
테스트 코드(MemoryMemberRepositoryTest)에서 검증할 때 두 방식의 차이를 확인해 보세요.
@Test
void 조회_테스트() {
Member member = new Member();
member.setName("spring");
repository.save(member);
// 1. Optional인 경우: .get()으로 꺼내야 비교 가능
Optional<Member> resultOpt = repository.findByName("spring");
assertThat(resultOpt.get()).isEqualTo(member);
// 2. List인 경우: 리스트 통째로 비교하거나 사이즈로 검증
List<Member> resultList = repository.findAll();
assertThat(resultList).contains(member); // member가 리스트에 포함되어 있는지 확인
assertThat(resultList.size()).isEqualTo(1); // 개수로 확인
}
💡 핵심 요약
- findById, findByName: "회원이 없을 수도 있으니 Optional 상자에 넣어서 줄게. 꺼내 쓰거나(get), 없으면 어떻게 할지 정해(orElse)."
- findAll: "데이터가 없으면 **빈 바구니(List)**를 줄게. 굳이 상자에 또 넣을 필요는 없어."
'INFLEARN' 카테고리의 다른 글
| [스프링 입문] 8. 스프링 데이터 JPA (0) | 2026.03.06 |
|---|---|
| [스프링 입문] 5. 컴포넌트 스캔과 자동 의존관계 설정(@Componet와 @Bean) (0) | 2026.03.06 |
| [스프링 입문] 4. JUnit5 테스트 코드 작성 (0) | 2026.03.03 |
| [스프링 입문] 2.MVC 템플릿 엔진 vs API 방식 (0) | 2026.03.03 |
| [스프링 입문] 1. Spring Boot에서 정적 페이지 로드 순서 (0) | 2026.03.03 |