Optional<T> 는 NPE: NullPointerException 을 피하기 위한 클래스이다
Optional<T> 는 null이 될 수 있는 값을 감싸는 Wrapper 클래스로, null 이 오더라도 NPE가 발생하지 않게 해주고, Optional<T>는 클래스이기 때문에 다양한 메소드를 제공한다
어떤 데이터가 null이 올 수 있는 경우 해당 값을 Optional<> 로 감싸고, orElse 또는 orElseGet 메소드를 사용해 값이 없는 경우라도 NPE를 발생시키지 않고 값을 가져올 수 있다
// Optional의 value는 값이 있을 수도 있고 null 일 수도 있다.
// getName() 은 값이 있을 수도, null 일 수도.
Optional<String> optional = Optional.ofNullable(getName());
String name = optional.orElse("anonymous"); // 값이 없다면 "anonymous" 를 리턴
<회원관리 예제에서 Optional<T> 이해하기>
package hello.hellospring.repository;
import ..
// 실무에서는 동시성문제때문에 ConcurrentHashMap, AtomicLong 사용
public class MemoryMemberRepository implements MemberRepository{
// value가 Member타입인 이유: name외에 다른정보가 들어갈 수 있기때문
private static Map<Long, Member> store = new HashMap<>();
private static long sequence = 0L;
@Override
public Member save(Member member) {
member.setId(++sequence);
store.put(member.getId(), member);
return member;
}
// ***
@Override
public Optional<Member> findById(Long id) {
// 결과로 null이 반환될 가능성
return Optional.ofNullable(store.get(id));
}
// ***
@Override
public Optional<Member> findByName(String name) {
// name은 중복이 가능하기때문에 stream()으로 돌려서 찾기
return store.values().stream()
.filter(member -> member.getName().equals(name))
.findAny();
}
@Override
public List<Member> findAll() {
return new ArrayList<>(store.values());
}
public void clearStore(){
store.clear();
}
}
테스트코드)
*Assertions 는 junit 이 아닌 assertj 에 있는 것을 사용함
package hello.hellospring.repository;
import ..
class MemoryMemberRepositoryTest {
MemoryMemberRepository repository = new MemoryMemberRepository();
// 테스트마다 서로 의존관계없이 설계되야함,
// 테스트 하나 끝날때마다 저장소나 공용데이터를 지워야한다
@AfterEach
public void afterEach(){
repository.clearStore();
}
@Test
public void save(){
Member member = new Member();
member.setName(("spring"));
repository.save(member);
// ***
Member result = repository.findById(member.getId()).get();
//Assertions.assertEquals(member, result);
//Assertions.assertThat(result).isEqualTo(member);
assertThat(result).isEqualTo(member);
}
@Test
public void findByName(){
Member member1 = new Member();
member1.setName("spring1");
repository.save(member1);
Member member2 = new Member();
member2.setName("spring2");
repository.save(member2);
// ***
Member result = repository.findByName("spring1").get(); // get()하면 옵셔널 까서꺼낼수있다
assertThat(result).isEqualTo(member1);
}
++ 보충설명
// 원래 반환타입은 Optional
Optional<Member> result = repository.findById(member.getId());
// get() 을 이용하면 옵셔널을 까서 꺼낼 수 있다(테스트코드에서는 종종 사용)
Member result = repository.findById(member.getId()).get();
위의 테스트 이어서)
@Test
public void findAll(){
Member member1 = new Member();
member1.setName("spring1");
repository.save(member1);
Member member2 = new Member();
member2.setName("spring2");
repository.save(member2);
List<Member> result = repository.findAll();
assertThat(result.size()).isEqualTo(2);
}
}
출처: https://mangkyu.tistory.com/70 [MangKyu's Diary]
'Spring' 카테고리의 다른 글
[Spring] 싱글톤 컨테이너와 @Configuration (0) | 2021.11.28 |
---|---|
[Spring] @Configuration, @Bean 이해하기 (0) | 2021.11.26 |
[Spring] DI : Dependency Injection (0) | 2021.08.28 |
[Spring] 정적컨텐츠, MVC와 템플릿엔진, API (0) | 2021.08.23 |
[Spring] Windows에서 cmd로 빌드&제거 (feat. IntelliJ) (0) | 2021.08.22 |