inblog logo
|
DailyCoding
    Spring Boot

    10-6. Optional

    박은서's avatar
    박은서
    Feb 06, 2026
    10-6. Optional
    Contents
    1. Optional<T>1️⃣ Optional<T> 이란?2️⃣ Optional이 필요한 이유3️⃣ Optional 생성 방법4️⃣ 값 확인 및 추출5️⃣ map / flatMap / filter (핵심)6️⃣ Optional 사용 시 권장 규칙 (중요)7️⃣ Optional vs null (요약 비교)8️⃣ 흔한 안티패턴9️⃣ 실습

    1. Optional<T>

    1️⃣ Optional<T> 이란?

    1) 기본 개념

    • 값이 있을 수도 있고 없을 수도 있는 상황을 명시적으로 표현하기 위한 컨테이너 타입
    Optional<T>
    • 내부에 단 하나의 값 또는 값 없음(empty) 상태를 가짐
    • null을 직접 담지 않음
    • Java 8부터 도입

    2) 핵심 목적

    • null로 인한 오류(특히 NullPointerException)를 줄이고, API의 의도를 분명히 하는 것

    2️⃣ Optional이 필요한 이유

    1) 기존 방식의 문제

    String name = user.getName(); if (name != null) { System.out.println(name.toUpperCase()); }
    • null 체크를 깜빡하기 쉽다
    • 메서드 시그니처만 봐서는 null이 올 수 있는지 알기 어렵다
    • NullPointerException의 주요 원인

    2) Optional 사용 시

    Optional<String> name = user.getName(); name.ifPresent(n -> System.out.println(n.toUpperCase()));
    • “이 값은 없을 수도 있다”는 사실이 타입으로 드러남
    • 호출자가 반드시 처리하도록 유도

    3️⃣ Optional 생성 방법

    1) 값이 확실히 있을 때

    Optional<String> opt = Optional.of("hello");
    ⚠️ null 전달 시 즉시 NullPointerException

    2) 값이 있을 수도, 없을 수도 있을 때

    Optional<String> opt = Optional.ofNullable(value);
    • value == null → Optional.empty()
    • 가장 흔히 사용됨

    3) 빈 Optional

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

    4️⃣ 값 확인 및 추출

    1) 존재 여부 확인

    if (opt.isPresent()) { System.out.println(opt.get()); }
    • 가능은 하지만 권장되지 않음
    • 결국 null 체크와 다를 바 없음

    2) ifPresent (권장)

    opt.ifPresent(value -> System.out.println(value));

    3) 기본값 제공

    String result = opt.orElse("default");
    ⚠️ orElse는 값이 있어도 인자가 항상 평가됨
    String result = opt.orElseGet(() -> expensiveOperation());
    • 필요할 때만 실행 → 성능상 더 안전

    4) 값이 없으면 예외

    String result = opt.orElseThrow();
    String result = opt.orElseThrow(() -> new IllegalStateException("값 없음"));

    5️⃣ map / flatMap / filter (핵심)

    1) map – 값 변환

    Optional<String> opt = Optional.of("java"); Optional<Integer> length = opt.map(String::length);
    • 값이 없으면 자동으로 empty 유지

    2) flatMap – Optional 중첩 방지

    Optional<Optional<String>> ❌ Optional<String> ✔
    Optional<User> user; Optional<String> email = user.flatMap(User::getEmail);
    getEmail()이 Optional<String>을 반환할 때 사용

    3) filter – 조건 만족 시만 유지

    Optional<String> opt = Optional.of("java"); opt.filter(s -> s.length() > 3) .ifPresent(System.out::println);

    6️⃣ Optional 사용 시 권장 규칙 (중요)

    ✅ 사용해야 할 곳

    • 메서드 반환 타입
    Optional<User> findUserById(long id)
    • 스트림 파이프라인
    • 값이 없음을 정상적인 흐름으로 표현할 때

    ❌ 피해야 할 곳

    ① 필드
    class User { Optional<String> name; // ❌ }
    ② 메서드 파라미터
    void print(Optional<String> name); // ❌
    ③ 컬렉션 대신
    Optional<List<User>> // ❌
    → List<User> (빈 리스트 사용)

    7️⃣ Optional vs null (요약 비교)

    항목
    null
    Optional
    의도 표현
    ❌ 불명확
    ✅ 명확
    타입 안정성
    ❌
    ✅
    NPE 위험
    높음
    낮음
    함수형 처리
    불가
    가능

    8️⃣ 흔한 안티패턴

    ❌ get() 남용

    opt.get(); // 값 없으면 예외

    ❌ isPresent + get

    if (opt.isPresent()) { return opt.get(); }

    ❌ Optional을 Serializable DTO 필드로 사용

    9️⃣ 실습

    1) Optional.of()

    package ex05; import java.util.Optional; public class OptEx01 { public static void main(String[] args) { // 1. Optional of Method String name = "ssar"; Optional<String> opt = Optional.of(name); // 선물박스 안에 값이 들어감 (of에는 null 들어갈 수 없음) System.out.println(opt.get()); // get() - 값이 무조건 있으니까 꺼내! 실제 코드에서는 사용 X System.out.println(opt.get().length()); } }
    notion image
    실제 코드에서는 사용할 일 없음. 무조건 값이 들어갈거면 그냥 String으로 받으면 됨

    2-1) Optional.ofNullable() - isEmpty()

    package ex05; import java.util.Optional; public class OptEx01 { public static void main(String[] args) { // 2. Optional nullable String name2 = null; Optional<String> opt2 = Optional.ofNullable(name2); if (opt2.isPresent()) { // 값이 있으면 System.out.println(opt2.get()); } if (opt2.isEmpty()) { // null이면 throw new RuntimeException("name2에 값이 없어요"); } } }
    notion image

    2-2) Optional.ofNullable() - isPresent()

    package ex05; import java.util.Optional; public class OptEx01 { public static void main(String[] args) { // 2. Optional nullable String name2 = "cos"; Optional<String> opt2 = Optional.ofNullable(name2); if (opt2.isPresent()) { // 값이 있으면 System.out.println(opt2.get()); } if (opt2.isEmpty()) { // null이면 throw new RuntimeException("name2에 값이 없어요"); } } }
    notion image

    3-1) orElseThrow() - ①홀수

    package ex05; import java.util.Optional; public class OptEx01 { static String download(int i){ if(i % 2 == 0){ return null; }else{ return i+""; } } public static void main(String[] args) { // 3. orElse String name3 = download(1); // 짝수 = null, 홀수 = 값 Optional<String> opt3 = Optional.ofNullable(name3); // 3-1. orElseThrow String value1 = opt3.orElseThrow(() -> new RuntimeException("opt3에 값이 없어요")); System.out.println("value1 : " + value1); // 3-2. orElse } }
    notion image

    3-1) orElseThrow() - ②짝수

    package ex05; import java.util.Optional; public class OptEx01 { static String download(int i){ if(i % 2 == 0){ return null; }else{ return i+""; } } public static void main(String[] args) { // 3. orElse String name3 = download(2); // 짝수 = null, 홀수 = 값 Optional<String> opt3 = Optional.ofNullable(name3); // 3-1. orElseThrow String value1 = opt3.orElseThrow(() -> new RuntimeException("opt3에 값이 없어요")); System.out.println("value1 : " + value1); // 3-2. orElse } }
    notion image

    3-2) orElse() - ①홀수

    package ex05; import java.util.Optional; public class OptEx01 { static String download(int i){ if(i % 2 == 0){ return null; }else{ return i+""; } } public static void main(String[] args) { // 3. orElse String name3 = download(1); // 짝수 = null, 홀수 = 값 Optional<String> opt3 = Optional.ofNullable(name3); // 3-1. orElseThrow String value1 = opt3.orElseThrow(() -> new RuntimeException("opt3에 값이 없어요")); // System.out.println("value1 : " + value1); // 3-2. orElse String value2 = opt3.orElse("0"); System.out.println("value2 : " + value2); } }
    notion image

    3-2) orElse() - ②짝수

    package ex05; import java.util.Optional; public class OptEx01 { static String download(int i){ if(i % 2 == 0){ return null; }else{ return i+""; } } public static void main(String[] args) { // 3. orElse String name3 = download(2); // 짝수 = null, 홀수 = 값 Optional<String> opt3 = Optional.ofNullable(name3); // 3-2. orElse String value2 = opt3.orElse("0"); System.out.println("value2 : " + value2); // 3-1. orElseThrow // String value1 = opt3.orElseThrow(() -> new RuntimeException("opt3에 값이 없어요")); // System.out.println("value1 : " + value1); } }
    notion image
    Share article
    Contents
    1. Optional<T>1️⃣ Optional<T> 이란?2️⃣ Optional이 필요한 이유3️⃣ Optional 생성 방법4️⃣ 값 확인 및 추출5️⃣ map / flatMap / filter (핵심)6️⃣ Optional 사용 시 권장 규칙 (중요)7️⃣ Optional vs null (요약 비교)8️⃣ 흔한 안티패턴9️⃣ 실습

    DailyCoding

    RSS·Powered by Inblog