NullPointerException(NPE) 문제
// 이름이 있으면 이름을 대문자로 출력, 없으면 "UNKNOWN"을 출력해라.
static void findAndPrint(Long id) {
Optional<String> optName = findNameById(id);
String name = optName.orElse("UNKNOWN");
System.out.println(id + ": " + name.toUpperCase());
}
static Optional<String> findNameById(Long id) {
String findName = map.get(id);
Optional<String> optName = Optional.ofNullable(findName);
return optName;
}
Optional.of(T value)
Optional.ofNullable(T value)
Optional.empty()

public class OptionalRetrievalMain {
public static void main(String[] args) {
// 예제: 문자열 "Hello"가 있는 Optional과 비어있는 Optional 준비
Optional<String> optValue = Optional.of("Hello");
Optional<String> optEmpty = Optional.empty();
// isPresent(): 값이 있으면 true
System.out.println("=== 1. isPresent() / isEmpty() ===");
System.out.println("optValue.isPresent() = " + optValue.isPresent());
System.out.println("optEmpty.isPresent() = " + optEmpty.isPresent());
System.out.println("optEmpty.isEmpty() = " + optEmpty.isEmpty());
// get() : 직접 내부 값을 꺼냄, 값이 없으면 예외 (NoSuchElementException)
System.out.println("=== 2. get() ===");
String getValue = optValue.get();
System.out.println("getValue = " + getValue);
//String getValue2 = optEmpty.get(); // 예외 발생 -> 주석 처리
// 값이 있으면 그 값, 없으면 지정된 기본값 사용
System.out.println("=== 3. orElse() ===");
String value1 = optValue.orElse("기본값");
String empty1 = optEmpty.orElse("기본값");
System.out.println("value1 = " + value1);
System.out.println("empty1 = " + empty1);
// 값이 없을 때만 람다(Supplier)가 실행되어 기본값 생성
System.out.println("=== 4. orElseGet() ===");
String value2 = optValue.orElseGet(() -> {
System.out.println("람다 호출 - optValue");
return "New Value";
});
String empty2 = optEmpty.orElseGet(() -> {
System.out.println("람다 호출 - optEmpty");
return "New Value";
});
System.out.println("value2 = " + value2);
System.out.println("empty2 = " + empty2);
// 값이 있으면 반환, 없으면 예외 발생
System.out.println("=== 5. orElseThrow() ===");
String value3 = optValue.orElseThrow(() -> new RuntimeException("값이 없습니다!"));
System.out.println("value3 = " + value3);
try {
String empty3 = optEmpty.orElseThrow(() -> new RuntimeException("값이 없습니다!"));
System.out.println("empty3 = " + empty3); // 실행되지 않음
} catch (Exception e) {
System.out.println("예외 발생: " + e.getMessage());
}
// Optional을 반환
System.out.println("=== 6. or() ===");
Optional<String> result1 = optValue.or(() -> Optional.of("Fallback"));
System.out.println(result1);
Optional<String> result2 = optEmpty.or(() -> Optional.of("Fallback"));
System.out.println(result2);
}
}

public class OptionalProcessingMain {
public static void main(String[] args) {
Optional<String> optValue = Optional.of("Hello");
Optional<String> optEmpty = Optional.empty();
// 값이 존재하면 Consumer 실행, 없으면 아무 일도 하지 않음
System.out.println("=== 1. ifPresent() ===");
optValue.ifPresent(v -> System.out.println("optValue 값: " + v));
optEmpty.ifPresent(v -> System.out.println("optEmpty 값: " + v)); // 실행 X
// 값이 있으면 Consumer 실행, 없으면 Runnable 실행
System.out.println("=== 2. ifPresentOfElse() ===");
optValue.ifPresentOrElse(
v -> System.out.println("optValue 값: " + v),
() -> System.out.println("optValue는 비어있음")
);
optEmpty.ifPresentOrElse(
v -> System.out.println("optEmpty 값: " + v),
() -> System.out.println("optEmpty는 비어있음")
);
// 값이 있으면 Function 적용 후 Optional로 반환, 없으면 Optional.empty()
System.out.println("=== 3. map() ===");
Optional<Integer> lengthOpt1 = optValue.map(String::length);
System.out.println("optValue.map(String::length) = " + lengthOpt1);
Optional<Integer> lengthOpt2 = optEmpty.map(String::length);
System.out.println("optEmpty.map(String::length) = " + lengthOpt2);
// map()과 유사하나, 이미 Optional을 반환하는 경우 중첩을 제거
System.out.println("=== 4. flatMap() ===");
System.out.println("[map]");
// Optional[Hello] -> Optional[Optional[HELLO]]
Optional<Optional<String>> nestedOpt = optValue.map(s -> Optional.of(s));
System.out.println("optValue = " + optValue);
System.out.println("nestedOpt = " + nestedOpt);
System.out.println("[flatMap]");
// flatMap을 사용하면 한 번에 평탄화
// Optional[Hello] -> Optional[HELLO]
Optional<String> flattenedOpt = optValue.flatMap(s -> Optional.of(s));
System.out.println("optValue = " + optValue);
System.out.println("flattenedOpt = " + flattenedOpt);
System.out.println("=== 5. filter() ===");
// 값이 있고 조건을 만족하면 그 값을 그대로, 불만족시 Optional.emtpy()
Optional<String> filtered1 = optValue.filter(s -> s.startsWith("H"));
Optional<String> filtered2 = optValue.filter(s -> s.startsWith("X"));
System.out.println("filter(H) = " + filtered1); // Optional[Hello]
System.out.println("filter(X) = " + filtered2); // Optional.empty
System.out.println("=== 6. stream() ===");
// 값이 있으면 단일 요소 스트림, 없으면 빈 스트림
optValue.stream()
.forEach(s -> System.out.println("optValue.stream() -> " + s));
// 값이 없으므로 실행 안 됨
optEmpty.stream()
.forEach(s -> System.out.println("optEmpty.stream() -> " + s));
}
}