ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • 자바의 Optional 클래스
    CS/JAVA 2025. 2. 16. 01:34

    자바 프로그래밍에서는, NullPointerException 예외가 자주 발생하는데요, 이 예외는 null값을 역참조하기 때문입니다.

    Optional 클래스는 이런 문제를 해결하기 위해 등장했습니다.

     

    Optional은 값이 있을 수도 있고 없을 수도 있는 객체를 감싸는 래퍼 클래스입니다. 이를 통해 명시적으로 해당 값이 null일 수 있음을 표현할 수 있으며, NullPointerException을 방지할 수 있는 API를 제공합니다.

     

    예를들어, null값인 String에서 length()를 호출하면 NullPointerException이 발생합니다.

    하지만 Optional로 감쌀 경우 NullPointerException의 발생을 방지할 수 있습니다.

    String value = null;
    System.out.println(value.length()); // NullPointerException 발생
    
    Optional<String> optionalValue = Optional.ofNullable(null);
    System.out.println(optionalValue.map(String::length).orElse(0)); // 0 출력

     

     

    저의 경우에 Optinal을 가장 많이 사용한 예시는 JPA로 데이터를 조회해올 때입니다.

    Member 객체를 조회하고자 할 때,

    다음과 같이 findByName 메서드의 반환값을 Member객체로 한다면, 조회한 name을 가진 Member가 없을 경우 예외가 터집니다.

    public interface MemberRepository extends JpaRepository<Member, Long> {
        Member findByName(String name);
    }
    
    @Service
    @RequiredArgsConstructor
    public class Service{
    	private final MemberRepository memberRepository;
    	
    	Member getMember(String name){
                Member member  = memberRepository.findByName(name);//조회된 데이터가 없으면 예외 발생
                return member;
        }
    }

     

    하지만 findByName 메서드의 반환값을 Optinal로 한다면, 조회한 name을 가진 Member가 없어도 예외가 터지지 않습니다.

    Optinal은 null일 경우 ~~ 때문입니다.

    public interface MemberRepository extends JpaRepository<Member, Long> {
        Optional<Member> findByName(String name);
    }
    
    @Service
    @RequiredArgsConstructor
    public class MemberService{
    	private final MemberRepository memberRepository;
    	
    	Member getMember(String name){
                Optional<Member> optional  = memberRepository.findByName(name); //조회된 데이터가 없어도 예외가 발생하지 않음
                return optional.orElse(null);// 값이 있을경우 Member 반환, 없으면 null 반환
        }
    }

     

     

    Optional 객체 생성하기

    Optional 객체를 생성하는 방법은 여러가지입니다.

     

    1. Optional.empty()

    명시적으로 값이 비어있는 Optional 객체를 표현할 때 사용합니다.

    Optional emptyOptional = Optional.empty();

     

    2. Optional.of()

    null이 아닌 값을 갖는 Optional 객체를 생성합니다. 만약 value가 null이라면 NullPointerException이 발생합니다.

    Optional optional1 = Optional.of("value");
    Optional optional2 = Optional.of(null); //NullPointerException 발생

     

    3. Optional.ofNullable()

    값이 null일 수도 있는 경우에 사용됩니다. value가 null이면 비어있는 Optional 객체를, 그렇지 않으면 해당 값을 갖는 Optional 객체를 생성합니다.

    Optional nullableOptional = Optional.ofNullable("value");

     

     

    Optional의 주요 메서드 - 값 가져오기

    1. get()

    get() 메서드는 Optional에 있는 값을 바로 가져오는 메서드입니다. 만약 Null인 경우 NPE가 발생하게 됩니다.

    Optional<String> optional = Optional.of("value");
    
    System.out.println(optional.get());

     

    2. isPresent(), isEmpty()

    isPresent() 메서드는 값이 Null이 아니면 true를 Null이면 false를 리턴하고, isEmpty()는 반대로 Null이면 true를 아니면 false를 리턴하는 메서드입니다.

    Optional<String> optional = Optional.of("value");
    
    if(optional.isPresent()){
    	System.out.println(optional.get());
    }
    
    if(optional.isEmpty()){
    	System.out.println("is empty");
    }

     

    3. ifPresent()

    Optional 객체에 값이 존재하면 람다식(Consumer 함수형 인터페이스)을 실행하고, 값이 없으면 아무 일도 하지 않는 메서드입니다.

    Optional<String> optional = Optional.of("value");
    
    optional.ifPresent((value) -> System.out.println("값이 존재합니다: " + value));

     

     

     

    Optional의 주요 메서드 - 종료 연산

    1. orElse()

    Optional 객체에 값이 존재하면 그 값을 반환하고, 값이 없으면 미리 지정한 기본값(other)을 반환하는 메서드입니다.

    Optional<String> optional1 = Optional.of("value");
    Optional<String> optional2 = Optional.ofNullable(null);
    
    System.out.println(optional1.orElse("defualt")); // "value" 출력
    System.out.println(optional2.orElse("defualt")); // "defualt" 출력

     

    2. orElseGet()

    Optional 객체에 값이 존재하면 그 값을 반환하고, 값이 없으면 람다식(Supplier)을 실행하여 동적으로 값을 생성하는 메서드입니다.

    Optional<String> optional = Optional.ofNullable(null);
    
    System.out.println( optional.orElseGet(() -> new String("Default Value"))); // "Default Value" 출력

     

    3. orElseThrow()

    Optional 객체에  값이 존재하면 반환하고, 없으면 예외를 발생시키는 메서드입니다.

    Optional<String> optional = Optional.ofNullable(null);
    
    String result = optional.orElseThrow(() -> new RuntimeException("값이 없습니다!")); //RuntimeException 발생
    
    System.out.println(result); // 실행되지 않음

     

     

     

    Optional의 주요 메서드 - 중간 연산

    1. map(Function)

    Optional 내부의 값을 변환할 때 사용합니다.

    값이 존재하면 변환을 적용한 새로운 Optional을 반환하고, 값이 없으면 그대로 Optional.empty()를 반환합니다.

    Optional<String> optional = Optional.of("hello");
    
    String string = optional.map(String::toUpperCase).orElse("empty");
    
    System.out.println(string); //"HELLO" 출력

     

    2. filter()

    Optional 내부 값이 특정 조건을 만족하면 유지하고, 그렇지 않으면 Optional.empty()를 반환하는 메서드입니다.

    Optional<String> optional = Optional.of("hello");
    
    Optional<String> result1 = optional.filter(value -> value.equals("hello")); // "hello"이면 유지, 아니면 Optional.empty()
    Optional<String> result2 = optional.filter(value -> value.equals("world")); // "world"이면 유지, 아니면 Optional.empty()
    
    System.out.println(result1.orElse("is Empty")); //"hello" 출력
    System.out.println(result2.orElse("is Empty")); //"is Empty" 출력

     

    3. flatMap(Function)

    Optional<Optional<T>> 같은 중첩된 OptionalOptional<T>로 변환하는 메서드입니다.

    내부 값이 Optional이라면 중첩을 풀어주고, 값을 없으면 그대로 Optional.empty()를 반환합니다.

    Optional<Optional<String>> optional = Optional.of(Optional.of("hello"));
    
    Optional<String> result = optional.flatMap(opt -> opt);
    
    System.out.println(result); //"hello" 출력
    class Member {
        private Optional<String> name;
    
        public Optional<String> getName() { return name; }
    }
    
    
    public class FlatMapExample {
        public static void main(String[] args) {
            Member = new Member("Alice");
            
            Optional<Member> optionalMember = Optional.of(member);
            
            Optional<String> result = optionalMember.flatMap(Member::getName);
            
            System.out.println(result); //"Alice" 출력
        }
    }

     

Designed by Tistory.