티스토리 뷰

개발/JAVA

[JAVA] Optional 클래스

애쿠 2023. 1. 26. 01:37

 

JAVA 8 부터 지원하기 시작한 클래스. NPE(NullPointerException) 예방 용도로 만들어진 클래스다. Optional 클래스도 stream과 같이 중간연산이 있지만, 써본적도 없고 사용할 일도 없을 것 같기 때문에 따로 다루진 않겠다.


1. Optional 생성하기

Optional.empty() -> 빈 optional 객체 생성
Optional.of() -> 특정 값을 같는 Optional 객체 생성
Optional.ofNullbale() -> null을 가질수도 있는 Optinal 객체 생성

Optional.ofNullbale() 의 경우 파라미터의 값이 null일 경우 Optional.empty를 return 한다.

 

2. Optional 구현 매서드

get() -> Optional 객체의 값 반환한다.(선언한 타입을 return)
isPresent(),isEmpty() -> Optional 객체에 값이 있는지 판별
orElse() -> 저장된 값이 존재하면 그 값을 반환하고, 값이 존재하지 않으면 파라미터의 값을 반환한다.
orElseGet()	-> 저장된 값이 존재하면 그 값을 반환하고, 값이 존재하지 않으면 파라미터의 람다식 결과값을 반환한다.
orElseThrow() -> 저장된 값이 존재하면 그 값을 반환하고, 값이 존재하지 않으면 파라미터의 예외를 발생시킨다.

orElse()와 orElseGet()는 약간의 차이가 있는데,

  • orElse: 파라미터로 값을 받는다.
  • orElseGet: 파라미터로 함수형 인터페이스(함수)를 받는다.

 

이 부분에만 있는게 아니다.


orElse의 경우 파라미터로 함수를 넘길 경우, Optional에 값이 있던 없던 "무조건" 한번 함수를 실행하니 구현에 있어서 확인이 꼭 필요하다.

 

이럴 경우가 있겠나 싶겠지만, 여기에서 잘 다뤄주었으니 참고해보면 좋을 것 같다.(실 개발에서는 거의 없는 경우 같다. 보통 orElseGet을 쓰기 때문)

3. 그래서 어떻게 써아하나

3.1 잘못된 사용의 예

Optional 클래스는 NPE에 안전해지기 위해 설계되었다고 하지만 개발을 하다보면 때로는 null이 필요한 경우도 있으며, Optional을 잘못 사용하게 되면 되려 NPE를 마주하게된다. 실제로 내가 개발하다 마주한 케이스다.

// 단순 예시 정확한 코드가 아닐 수 있습니다.
Person person = Optional.ofNullable(personMapper.getPerson()).orElseGet(Person::new);

db를 조회했을 때 아무것도 없을 경우, person이 null인 상황을 피하기 위해 Optional 클래스를 이용해 빈 객체를 만들어 준 경우다. 여기까진 좋다.


하지만 문제는 이 다음에 person이 가진 데이터에 바로 접근할 경우 문제가 발생할 수 있다.

// 이 코드는 null sage할까?
if(person != null) {
	System.out.println(person.getName())
}

정답은 No다. person의 데이터가 없을 경우 빈 객체가 있기 때문에 조건문을 통과하지만 person의 name에 접근할 경우 데이터가 없기 때문에 NPE가 발생한다.

 

3.2 제대로 사용해보자

사실 저렇게 Optional 클래스를 이용해 null에 대한 예외 처리를 하는건 옳은 방법이 아니다. Optaional 클래스로 null을 처리 하는 방법은 많겠지만 개인적으로 선호하는 방법은 두 가지가 있다.

 

1. orElse(null)을 붙인다.

// 단순 예시 정확한 코드가 아닐 수 있습니다.
Person person = Optional.ofNullable(personMapper.getPerson()).orElse(null);

이 경우 조회 시 반환값이 null일 경우 null을 반환한다. 예시로는 받아들이기 힘든데, 다른 예시로 stream의 findFirst, findAny 등에서 Optional 값이 반환값인 경우 유용하게 쓸 수 있다.

Person person = personMapper.getPerons().stream().findFirst().orElse(null);

위와 같이 작성하면 아래 코드가 null safe해진다.

if(person != null) {
	System.out.println(person.getName())
}

 

2. Optional로 선언 후 isPresent()를 사용하는 방법


 이 방법이 조금 더 직관적이다. 아래와 같이 stream에서 Optional을 반환하는 값을 그대로 받아 null 체크하는 부분을 수정한다.

Optional<Person> person = personMapper.getPerson().stream().findFirst();

if(person.isPresent()) {
	System.out.println(person.getName());
}

위 방법 모두 person 객체가 있을 때, name값이 무조건 존재할 것이라 가정했으니 이 부분에 대한 처리는 또 필요할 수 있다. NPE 문제가 이렇게 까다롭다.

 

자 여기까지 보고도, 아니 그럼 그냥 Optional 안쓰고도 null처리를 할 수 있잖아요... 라고한다면 솔직히 할말이 없다. 맞는 말이기 때문에...

 

그래서 자바 8에서 Optional이 처음 등장한 이후로 지금까지 계속 토론 중인 것 같다.

 

시간이 난다면 스택 오버플로우에서 있었던 Optional 사용법에 대한 토론을 참고하면 좋을 것 같다.

 

 이 블로그에서도 정리를 잘 해주었다.

 

4. 마치며

긴 글에 비해 결론은 보잘 것 없다. 굳이 안써도 문제 될 것 없다.

 

조금 더 직관적으로 코드를 만들어 줄 순 있으나, 로직 자체를 복잡하게 만들어 버릴 수 있기 때문이다.

 

NPE safe하게 코드를 짜는 방법은 한 가지만 있는 것이 아니니, 본인의 상황에 맞게 사용하면 될 것 같다.

'개발 > JAVA' 카테고리의 다른 글

[Java] 리스트 객체 내 중복 제거(List to Set)  (0) 2023.01.26
[JAVA] 이중콜론(::) 표현식  (0) 2023.01.26
[JAVA] Collectors  (1) 2023.01.26
[JAVA] Stream  (1) 2023.01.26
[JAVA] 함수형 인터페이스  (1) 2023.01.26
공지사항
최근에 올라온 글
최근에 달린 댓글
Total
Today
Yesterday
링크
«   2024/10   »
1 2 3 4 5
6 7 8 9 10 11 12
13 14 15 16 17 18 19
20 21 22 23 24 25 26
27 28 29 30 31
글 보관함