Optional

μžλ°”μ—μ„œ μ›μ‹œ νƒ€μž…μ„ μ œμ™Έν•œ λͺ¨λ“  μ°Έμ‘° λ³€μˆ˜λŠ” null을 κ°€μ§ˆ 수 μžˆμ–΄, 이둜 인해 NullPointerException(NPE)이 λΉˆλ²ˆν•˜κ²Œ λ°œμƒν•œλ‹€.

public static void main(String[] args) {
    String str = "abc";
    if (str != null) {
        System.out.println(str.toUpperCase()); // ABC
    } else {
        System.out.println("null");
    }
}

μžλ°” 8μ—μ„œλŠ” Optional 클래슀λ₯Ό λ„μž…ν•˜μ—¬ λ©”μ„œλ“œ μ‹œκ·Έλ‹ˆμ²˜λ§Œ 보고도 null λ°˜ν™˜ κ°€λŠ₯성을 μ˜ˆμΈ‘ν•  수 있게 ν•˜λ©°, null 처리λ₯Ό κ°•μ œν•˜λŠ” 효과λ₯Ό μ€€λ‹€.

Optional 객체 생성

Optional은 null이 될 수 μžˆλŠ” 객체λ₯Ό κ°μ‹ΈλŠ” 래퍼 클래슀둜, null이 될 수 μžˆλŠ” 객체λ₯Ό λ‹΄κ³  μžˆλŠ” Optional 객체λ₯Ό 생성할 수 μžˆλ‹€.

public static void main(String[] args) {
    Map<String, String> map = Map.of("existKey", "existValue");
    Optional<String> opt1 = Optional.of(map.get("existKey")); //  `null`이 μ•„λ‹˜μ„ 보μž₯ν•  λ•Œ μ‚¬μš©
    Optional<String> opt2 = Optional.ofNullable(map.get("notExistKey")); // `null`일 μˆ˜λ„ μžˆμ„ λ•Œ μ‚¬μš©
    Optional<String> opt3 = Optional.empty(); // `null`μž„μ„ λͺ…μ‹œμ μœΌλ‘œ λ‚˜νƒ€λ‚Ό λ•Œ μ‚¬μš©
}

λ©”μ„œλ“œ

μž…λ ₯ κ°’ null

μž…λ ₯ κ°’ null μ•„λ‹˜

Optional.of(T value)

NullPointerException λ°œμƒ

Optional 객체 생성 (값을 λ‹΄κ³  있음)

Optional.ofNullable(T value)

Optional.empty() λ°˜ν™˜

Optional 객체 생성 (값을 λ‹΄κ³  있음)

Optional.empty()

-(null을 λ‹΄κ³  μžˆλŠ” Optional 객체 생성

-(null을 λ‹΄κ³  μžˆλŠ” Optional 객체 생성

Optional 객체 쑰회

get() λ©”μ„œλ“œ

Optional 객체에 λ‹΄κΈ΄ 값을 κ°€μ Έμ˜€κΈ° μœ„ν•΄μ„œλŠ” 기본적으둜 get() λ©”μ„œλ“œλ₯Ό μ‚¬μš©ν•΄μ„œ κ°€μ Έμ˜¬ 수 μžˆλ‹€.

ν•˜μ§€λ§Œ λΉ„μ–΄μžˆλŠ” Optional 객체에 get()을 ν˜ΈμΆœν•˜λ©΄ NoSuchElementException이 λ°œμƒν•  수 있기 λ•Œλ¬Έμ—, ifPresent()와 κ²°ν•©ν•˜μ—¬ μ‚¬μš©ν•΄λ³Ό 수 μžˆλ‹€.

ν•˜μ§€λ§Œ μœ„μ™€ 같은 방식은 if (value != null) { ... } μ½”λ“œμ™€ 본질적으둜 λ‹€λ₯΄μ§€ μ•ŠμœΌλ©°, Optional의 μž₯점을 ν™œμš©ν•˜μ§€ λͺ»ν•œλ‹€.

μ˜¬λ°”λ₯Έ Optional κ°’ 쑰회 및 처리 방법

Optional 객체의 값을 μ‘°νšŒν•˜κ³  μ²˜λ¦¬ν•˜λŠ” μœ„ν•΄ λ‹€μ–‘ν•œ λ©”μ„œλ“œκ°€ μ œκ³΅λœλ‹€.

λ©”μ„œλ“œ
값이 μžˆμ„ λ•Œ
값이 없을 λ•Œ

ifPresent(Consumer<? super T> action)

Consumer μ‹€ν–‰

아무 λ™μž‘λ„ ν•˜μ§€ μ•ŠμŒ

ifPresentOrElse(Consumer<? super T> action, Runnable emptyAction)

Consumer μ‹€ν–‰

Runnable μ‹€ν–‰

orElse(T other)

값을 λ°˜ν™˜

전달 받은 인자λ₯Ό λ°˜ν™˜

orElseGet(Supplier<? extends T> other)

값을 λ°˜ν™˜

Supplierλ₯Ό μ‹€ν–‰ν•œ κ²°κ³Όλ₯Ό λ°˜ν™˜

orElseThrow(Supplier<? extends X> exceptionSupplier)

값을 λ°˜ν™˜

Supplierκ°€ μ œκ³΅ν•˜λŠ” μ˜ˆμ™Έλ₯Ό λ°œμƒ

orElse() vs orElseGet()

orElse()와 orElseGet()은 Optional이 λΉ„μ–΄μžˆμ„ λ•Œ λŒ€μ²΄ 값을 μ œκ³΅ν•˜λŠ” λ™μΌν•œ κΈ°λŠ₯을 κ°€μ§„ λ©”μ„œλ“œμ§€λ§Œ, 기본값을 μƒμ„±ν•˜λŠ” μ‹œμ μ—μ„œ 차이가 μžˆλ‹€.

  • orElse(T other): Optional에 값이 μžˆλ“  μ—†λ“  other 객체가 항상 생성

  • orElseGet(Supplier<? extends T> other): Optional에 값이 없을 λ•Œλ§Œ Supplier λžŒλ‹€μ‹μ΄ μ‹€ν–‰λ˜μ–΄ 기본값이 생성

λ•Œλ¬Έμ—, κΈ°λ³Έκ°’ 생성 λΉ„μš©μ΄ 큰 κ²½μš°μ—λŠ” orElseGet()을 μ‚¬μš©ν•˜λŠ” 것이 μ„±λŠ₯상 μœ λ¦¬ν•˜λ‹€.

Optional ν™œμš© μ‹œ 주의점

Optional은 λ‚¨μš©ν•˜λ©΄ 였히렀 μ½”λ“œλ₯Ό λ³΅μž‘ν•˜κ²Œ λ§Œλ“€ 수 μžˆλ‹€.

  • λ©”μ„œλ“œ λ°˜ν™˜ νƒ€μž…μœΌλ‘œλ§Œ μ‚¬μš©: Optional은 λ©”μ„œλ“œμ˜ λ°˜ν™˜ νƒ€μž…(return type)으둜 μ‚¬μš©λ˜λŠ” 것을 ꢌμž₯

  • ν•„λ“œ(멀버 λ³€μˆ˜)둜 μ‚¬μš© κΈˆμ§€: 클래슀의 ν•„λ“œ νƒ€μž…μœΌλ‘œ Optional을 μ‚¬μš©ν•˜λŠ” 것은 ꢌμž₯λ˜μ§€ μ•ŠμŒ

    • 직렬화 문제, JPA λ“±μ—μ„œμ˜ λΉ„ν˜Έν™˜μ„± 문제

  • λ©”μ„œλ“œ λ§€κ°œλ³€μˆ˜λ‘œ μ‚¬μš© κΈˆμ§€: λ§€κ°œλ³€μˆ˜λ‘œ null을 보낼 수 μžˆμ–΄ Optional 객체 μžμ²΄κ°€ null이 될 수 있음

    • λ©”μ„œλ“œ μ˜€λ²„λ‘œλ”©μœΌλ‘œ ν•΄κ²°ν•˜λŠ” 것이 더 λ‚˜μŒ

  • μ»¬λ ‰μ…˜ λž˜ν•‘ κΈˆμ§€: μ»¬λ ‰μ…˜μ€ null을 λ°˜ν™˜ν•˜κΈ°λ³΄λ‹€ λΉ„μ–΄μžˆλŠ” μ»¬λ ‰μ…˜(예: Collections.emptyList())을 λ°˜ν™˜ν•˜λŠ” 것을 ꢌμž₯

Last updated

Was this helpful?