우당탕탕 개발일지

[Java] Java8, Optional 이란? 본문

Java

[Java] Java8, Optional 이란?

kyunge_ev 2022. 11. 11. 22:09

 🌈 Optional 

 

개발 시 가장 많이 발생하는 예외인 NPE(NullPointerException)을 피하기 위해 Null 여부를 검사하는데 Null 검사를 해야하는 변수가 많아 질 경우 코드가 복잡해지고 많아진다. 그래서 Null 대신 초기값을 사용하길 권장하는데 이 때, 사용하는 것을 Optional 이라고 한다.

  • JAVA8 부터 Optional<T> 클래스를 사용해 NPE를 방지할 수 있도록 도와줌
    • Optional 클래스는 제너릭(Generic)으로 값의 타입을 지정
  • Optional 클래스는 Null이 올 수 있는 값을 감싸는 래퍼(Wrapper) 클래스
    • Null 이더라도 바로 NPE가 발생하지 않음 👉 NPE(NullPointerException)를 방지
    • 클래스이기 때문에 각종 메소드를 제공해줌
      • .orElseThrow() / .orElse 등 편의기능을 사용하여 코드를 간결하게 만들 수 있다.
  • Optional은 값을 Wrapping 하고 다시 풀때 null일 경우 대체하는 함수를 호출
    → 오버헤드 발생 할 수 있으므로 잘 못 사용 시 시스템 성능 저하
    → 메서드의 반환 값이 절대 null이 아니라면 Optional 사용을 권장하지 않음

 

 🌈 Optional 생성 

📚 Optional.empty() ⇒ 값이 Null인 경우

  • 값이 null이라도 NPE를 발생시키지 않고, Optional.empty를 리턴
  • Optional 클래스 내부에서 static 변수로 empty 객체를 미리 생성하여 가지고 있음
    👉 빈 객체를 여러번 생성해줘야 하는 경우에도 1개의 empty 객체를 공유함으로써 메모리를 절약함
1
2
3
4
Optional<String> optional = Optional.empty();
 
System.out.println(optional); // 출력 : Optional.empty
System.out.println(optional.isPresent()); // 출력 : false
cs

 

📚 Optional.of() ⇒ 값이 Null이 아닌 경우

  • 값이 절대 null일 수 없는 경우 사용, 만약 null로 저장할 경우 NullPointerException 발생
1
Optional<String> optional = Optional.of("MyName");
cs

 

📚 Optional.ofNullbale() ⇒ 값이 Null일 수도, 아닐 수도 있는 경우

  • orElse , orElseGet 메서드를 사용하여 값이 없는 경우라도 안전하게 값을 가져올 수 있음
1
2
3
4
Optional<String> optional = Optional.ofNullable(getName());
 
// 값이 없다면 "Null"를 리턴
String name = optional.orElse("Null"); 
cs

 

 🌈 Optional이 제공하는 메소드 

📃 .filter()

  • filter 메소드의 인자인 람다식이 true이면 Optional 객체를 그대로 통과시키고, false라면 Optional.emty()를 return하여 추가로 처리되지 않도록 함.
1
2
3
4
5
String result1 = Optional.of("optional").filter((val) -> val.contains("opt")).orElse("Does not contain opt");
System.out.println(result1); //optional
 
String result2 = Optional.of("optional").filter((val) -> val.contains("abc")).orElse("Does not contain abc");
System.out.println(result2); //Does not contain abc
cs


 

📃 .map()

  • 입력받은 값을 다른 값으로 변환하는 메소드
  • abcde를 대문자 ABCDE로 변환
1
2
String result3 = Optional.of("abcde").map(String::toUpperCase).orElse("fail");
System.out.println(result3); //ABCDE
cs

 

📃 .isPresent()

  • 값이 존재한다면 true를 반환하고 존재하지 않으면 false를 반환
1
2
if (optionalLike.isPresent()){ // like가 존재한다면,
    likeRepository.delete(optionalLike.get()); // like를 삭제한다.
cs

 

📃 .ifPresent()

  • 람다식을 인자로 받는데, 값이 존재할 때만 람다식이 적용되고, 값이 존재하지 않으면 실행되지 않는다.
1
2
3
Optional.of("ABCDE").ifPresent(System.out :: println); //결과 : ABCDE
 
Optional.ofNullable(null).ifPresent(System.out :: println); //결과 : 아무것도 출력되지 않음
cs

 

📃 .get()

  • Optional 객체가 가지고 있는 value를 가지고옴 👉 만약 객체가 없다면, NoSuchElementException이 발생
1
2
if (optionalLike.isPresent()){ // like가 존재한다면,
    likeRepository.delete(optionalLike.get()); // like를 삭제한다.
cs

 

📃 .orElse()

  • Optional 객체가 Null이라면 orElse() 메소드가 지정된 값으로 return

 

📃 .orElseThrow()

  • 연산을 끝낸 후에도 Optional 객체가 Null이라면 예외 공급자 함수를 통해 예외를 발생
1
2
3
4
5
6
7
8
9
10
11
12
public CommentDeleteResponse delete(Long postsId, Long id, String userName) {
        // 게시물이 존재하지 않는 경우
        Post post = postRepository.findById(postsId)
                .orElseThrow(() -> new AppException(ErrorCode.POST_NOT_FOUND, ErrorCode.POST_NOT_FOUND.getMessage()));
        // ...
 
 
        return CommentDeleteResponse.builder()
                .message("포스트 삭제 완료")
                .id(postsId)
                .build();
}
cs

 

 

📢

그 외, Java9에서 추가된 or(), isPresentOrElse(), stream() 메소드와
Java10에서 추가된 인자를 받지 않는 orElseThrow() 메소드가 있다.
(추가로 블로그 수정예정)