공공부하자개발 · 영어 학습 노트
자바
고급모던 자바와 성능0/10 완료
  • 01제네릭과 와일드카드
  • 02멀티스레드와 동기화
  • 03람다식과 함수형 인터페이스
  • 04Stream API와 병렬 처리
  • 05Optional로 NPE 방지
  • 06메서드 활용 패턴 (고급)
  • 07Java 21 모던 문법
  • 08어노테이션·리플렉션·동적 프록시
  • 09CompletableFuture 심화와 가상 스레드 실전
  • 10JVM 메모리·GC·OOM 진단
사이트 소개개인정보처리방침연락처
© 2026 공부하자
홈 › 고급 › 05 / 10

Optional로 NPE 방지

섹션 7진행 0 / 10
1왜 배우는가2핵심 원리3코드 예제4응용 변형 예제5자주 하는 실수 (Tip)6연습 문제7정리‹ 이전다음 ›

6. 연습 문제

문제 1

record Product(String sku, String name, Integer discountRate) 에서 discountRate 는 null 일 수 있습니다(할인 없음).

Map<String, Product> catalog 에서 SKU 로 조회해 할인율이 있고 10% 이상이면 "name (rate%)", 할인이 없거나 10% 미만이면 "name", 상품이 없으면 "unknown sku" 를 반환하는 describe(String sku) 를 Optional 체인으로 작성하세요.

isPresent/get 을 쓰지 마세요.

정답 보기
java
import java.util.*;

public class Ex1 {
    record Product(String sku, String name, Integer discountRate) {}

    static final Map<String, Product> CATALOG = Map.of(
        "P1", new Product("P1", "Keyboard", 15),
        "P2", new Product("P2", "Mouse", 5),
        "P3", new Product("P3", "Monitor", null));

    static String describe(String sku) {
        return Optional.ofNullable(CATALOG.get(sku))
            .map(p -> Optional.ofNullable(p.discountRate())
                              .filter(r -> r >= 10)
                              .map(r -> p.name() + " (" + r + "%)")
                              .orElse(p.name()))
            .orElse("unknown sku");
    }

    public static void main(String[] args) {
        for (String sku : List.of("P1", "P2", "P3", "P9")) System.out.println(sku + " → " + describe(sku));
    }
}
// 출력:
// P1 → Keyboard (15%)
// P2 → Mouse
// P3 → Monitor
// P9 → unknown sku

문제 2

orElse 와 orElseGet 의 차이를 이용한 버그를 찾아 고치세요. 아래 SessionCache.get 은 캐시 히트 시에도 createSession 이 호출됩니다. 호출 횟수를 세어 수정 전후를 비교하는 코드를 작성하세요.

java
Map<String, String> cache = new HashMap<>();
int created = 0;
String get(String userId) {
    return Optional.ofNullable(cache.get(userId)).orElse(createSession(userId));
}
정답 보기
java
import java.util.*;

public class Ex2 {
    static final Map<String, String> cache = new HashMap<>();
    static int created = 0;

    static String createSession(String userId) { created++; String s = "sess-" + userId; cache.put(userId, s); return s; }

    static String getBuggy(String userId) {
        return Optional.ofNullable(cache.get(userId)).orElse(createSession(userId));   // 항상 생성
    }
    static String getFixed(String userId) {
        return Optional.ofNullable(cache.get(userId)).orElseGet(() -> createSession(userId));   // 미스 때만 생성
    }

    public static void main(String[] args) {
        for (int i = 0; i < 3; i++) getBuggy("kim");
        System.out.println("buggy: created = " + created);     // 3 (매번 생성)
        created = 0; cache.clear();
        for (int i = 0; i < 3; i++) getFixed("kim");
        System.out.println("fixed: created = " + created);     // 1
    }
}
// 출력:
// buggy: created = 3
// fixed: created = 1

문제 3

문자열 목록 ["42", "x", "", "7", null, "100"] 에서 정수로 파싱 가능한 것만 골라 합계를 구하세요. Optional<Integer> parse(String s) 를 만들고(null/빈 문자열/숫자 아님 → empty), 스트림에서 flatMap(Optional::stream) 으로 합치세요. 그리고 같은 목록의 첫 번째 파싱 가능한 값을 findFirst 로 구해 출력하세요.

정답 보기
java
import java.util.*;

public class Ex3 {
    static Optional<Integer> parse(String s) {
        return Optional.ofNullable(s)
            .map(String::strip)
            .filter(t -> !t.isEmpty() && t.matches("-?\\d+"))
            .map(Integer::valueOf);
    }

    public static void main(String[] args) {
        List<String> raw = Arrays.asList("42", "x", "", "7", null, "100");
        int sum = raw.stream().map(Ex3::parse).flatMap(Optional::stream).mapToInt(Integer::intValue).sum();
        System.out.println("sum = " + sum);

        Optional<Integer> first = raw.stream().map(Ex3::parse).flatMap(Optional::stream).findFirst();
        System.out.println("first = " + first.orElse(-1));
        System.out.println("parse(null) = " + parse(null) + ", parse(\"x\") = " + parse("x"));
    }
}
// 출력:
// sum = 149
// first = 42
// parse(null) = Optional.empty, parse("x") = Optional.empty
연습 문제
  • 문제 1
  • 문제 2
  • 문제 3
이전 섹션5 자주 하는 실수 (Tip)6 / 7다음 섹션7 정리