본문 바로가기

Language/JAVA

[자바] Optional이란? Optional 개념 및 사용법 orElse와 orElseGet 비교

 

Optional

 

JAVA8이후 추가된, 값이 있을수도 있고, 없을수도 있다는 것을 명시한 타입

null이 올 수도 있는 값을 한 겹 감싸서, 그 안에 null이 있더라도 NullPointerException이 터지지 않게 도와주는 클래스

클래스이기 때문에 .empty(), orElseThrow() 등 다양한 메서드 제공

 

 

- Optional 객체에 빈값을 명시적으로 넣는 방법

1. Optional.empty() - 빈값

empty() 메서드를 통해 opt1 객체에 빈 값을 넣는다.

Optional<String> opt1 = Optional.empty();

 

 

2. Optional.of() - 값이 null이 아닌 경우

절대 null 값을 가질 수 없는 경우에는 Optional.of() 생성한.

만약 Optional.of() Null 저장하려고 하면 NullPointerException 발생한다.

Optional<String> opt2 = Optional.of("hello");

 

 

3. Optional.ofNullable() - 값이 Null일수도, 아닐수도 있는 경우

null 수도 있는 경우에는 Optional.ofNullbale 생성한.

만약 null 값을 갖는 객체에 이후 접근한다면, orElse 또는 orElseGet 메소드를 이용해서 안전하게 값을 가져올 있다.

Optional<String> opt2 = Optional.ofNullable("hello"); //null 있을수도 있음을 의미

 

 

 

- Optional 객체에 접근하는 방법

1. Optional.get()

Optional 객체에 저장된 값이 null이면, NoSuchElementException 예외가 발생

Optional<String> opt2 = Optional.of("hello");
System.out.println(opt2.get());

 


2. Optional.isPresent()

값이 있다면 true를 반환, 없다면 false를 반환하여 분기처리에 사용할 수 있다.

Optional<String> opt1 = Optional.empty();
if(opt1.isPresent()){
    System.out.println(opt1.get().compareTo("abc"));
}else{
    System.out.println("값이 없습니다.");
}

 

 

Optional일 경우, 값이 있는지 없는지 체크하는 로직을 짜는 것이 좋다.

        Optional<String> myOptional = Optional.ofNullable("hello");
        if(myOptional.isPresent()){
            System.out.println(myOptional.get().length());
        }

 

 

3. Optional.orElse() 관련 메서드(orElse(), orElseGet(), orElseThrow()) 사용

 

(1) Optional.orElse()

  • 값이 존재하는 경우
    • 값이 이미 Optional에 존재한다면, 해당 값 자체를 반환
    • 추가적인 계산, 함수 실행 X
  • 값이 없는 경우
    • 인자로 전달된 값(other)이 반환
Optional<String> maybeString = Optional.ofNullable(getValue()); 
String result = maybeString.orElse("Default Value");

 

➡️ maybeString 값이 있다면 해당 값이 반환되고

➡️ 값이 없다면 "Default Value" 반환된다.

 

 

(2) Optional.orElseGet()

  • 값이 존재하는 경우
    • 값이 이미 Optional에 존재한다면, 해당 값 자체를 반환
    • 추가적인 계산, 함수 실행 X
  • 값이 없는 경우
    • 인자로 전달된 Supplier 함수를 사용하여 값을 생성 후, 반환
    • 이때, 추가적인 계산(함수 실행) 발생
Optional<String> maybeString = Optional.ofNullable(getValue()); 
String result = maybeString.orElseGet(() -> generateDefaultValue());

➡️ maybeString 값이 있다면 해당 값이 반환되고,

➡️ 값이 없다면 generateDefaultValue() 함수가 실행되어 결과가 반환된다.

 

 

(3) Optional.orElseThrow()

  • 값이 있으면 해당  return, 값이 존재하지 않으면 인수로 전달된 예외를 발생

에러 메시지 문구를 직접 넣을 수 있는 방식 : orElseThrow( () -> new 예외명("문구") )

시스템에서 지정된 에러 메시지만 확인하는 방식 : orElseThrow(예외명::new)

Optional<String> opt1 = Optional.empty();
int result = opt1.orElseThrow(()->new NoSuchElementException("객체에 값이 없습니다")).compareTo("abc");
System.out.println(result);

int result2 = opt1.orElseThrow(NoSuchElementException::new).compareTo("abc");
System.out.println(result2);

 

 

 

- orElse()와 orElseGet() 비교

💡 orElse는 값이 없는 경우 불필요한 함수를 호출하는 작업을 하기 때문에,
orElseGet보다 비효율적이므로 최대한 사용을 피해야 한다.
보통 값이 미리 존재하는 경우에는 .orElse()를, 값이 미리 존재하지 않는 경우에는 .orElseGet()을 많이 사용한다.

 

import java.util.Optional;

public class OptionalExample {
    public static void main(String[] args) {
        // 예제 1: 값이 있는 경우
        Optional<String> maybeString1 = Optional.of("Existing Value");

        // .orElse() 사용
        String result1_orElse = maybeString1.orElse(getDefaultValue());
        System.out.println("Result using orElse: " + result1_orElse);

        // .orElseGet() 사용
        String result1_orElseGet = maybeString1.orElseGet(() -> generateDefaultValue());
        System.out.println("Result using orElseGet: " + result1_orElseGet);

        // 예제 2: 값이 없는 경우
        Optional<String> maybeString2 = Optional.empty();

        // .orElse() 사용
        String result2_orElse = maybeString2.orElse(getDefaultValue());
        System.out.println("Result using orElse: " + result2_orElse);

        // .orElseGet() 사용
        String result2_orElseGet = maybeString2.orElseGet(() -> generateDefaultValue());
        System.out.println("Result using orElseGet: " + result2_orElseGet);
    }

    private static String getDefaultValue() {
        System.out.println("Generating default value");
        return "Default Value";
    }

    private static String generateDefaultValue() {
        System.out.println("Generating default value using supplier");
        return "Default Value from Supplier";
    }
}

 

실행결과

Result using orElse: Existing Value
Result using orElseGet: Existing Value
Generating default value
Result using orElse: Default Value
Generating default value using supplier
Result using orElseGet: Default Value from Supplier

 

  • 값이 있는 경우
    • .orElse()와 .orElseGet() 모두 값이 이미 존재할 때는 추가적인 계산이 발생하지 않다.
    • 경우 모두 "Existing Value" 반환된다.
  • 값이 없는 경우
    • .orElse()항상 값을 가져오기 위해 getDefaultValue() 메서드를 호출합니다.
    • .orElseGet() 값이 없는 경우에만 generateDefaultValue() 함수를 실행하고, 값이 이미 존재할 때는 실행되지 않습니다.

 

- 종류

기본형 타입 : OptionalInt, OptionalLong, OptionalDouble 자료형 사용

참조형 타입 : Optional<String> 처럼 제네릭 타입에 변수 타입을 넣어 사용