Optional 모범 사례
orElse, orElseGet, orElseThrow를 적용하고 Optional의 일반적인 안티 패턴을 피합니다.
Optional 모범 사례은(는) CoddyKit의 무료 Java Academy 강의입니다. 이것은 4개 중 4번째 강의입니다. 아래에서 전체 강의를 무료로 읽을 수 있으며, 내장 코드 에디터와 24/7 AI 튜터와 함께 브라우저에서 직접 실습할 수 있습니다. 이 강의는 Java Academy 학습 경로의 일부이며, 진행 상황이 웹과 CoddyKit 앱에 동기화됩니다. Java Academy 강의에는 총 4개의 강의가 포함되어 있습니다.
Optional 모범 사례
Optional은 올바르게 사용하면 강력한 도구입니다. 이 레슨에서는 실제 코드베이스의 구체적인 예를 통해 지켜야 할 사항과 피해야 할 사항을 다룹니다.
권장: 반환 형식으로 Optional 사용하기
Optional의 주된 사용 사례는 값을 찾지 못하거나 생성하지 못할 수 있는 메서드의 반환 형식으로 사용하는 것입니다.
import java.util.Optional;
// Good: signals to caller that result might be absent
public Optional<User> findByUsername(String username) { ... }
public Optional<Config> getConfig(String key) { ... }
public Optional<String> getHeader(String name) { ... }
// These are all cases where absence is a normal outcome,
// not an exceptional condition금지: 필드로 Optional 사용하기
Optional 필드는 객체 오버헤드를 추가하고 직렬화를 복잡하게 만듭니다. 클래스 내부의 선택적 필드에는 null 또는 센티널 값을 사용하십시오.
// BAD
class User {
private Optional<String> middleName; // wrong
}
// GOOD: use null for absent optional field
class User {
private final String middleName; // null = absent
public Optional<String> middleName() {
return Optional.ofNullable(middleName); // expose as Optional in getter
}
}
User u = new User(null); // null field
System.out.println(u.middleName().isPresent()); // false금지: 메서드 매개변수로 Optional 사용하기
Optional 매개변수를 사용하면 호출하는 쪽에서 불필요하게 값을 Optional로 감싸야 합니다. 대신 오버로드 또는 @Nullable을 사용하십시오.
// BAD
void sendNotification(String message, Optional<String> subject) { ... }
// caller must write: sendNotification("Hello", Optional.of("News"))
// GOOD: overloading
void sendNotification(String message) { sendNotification(message, null); }
void sendNotification(String message, String subject) {
// subject may be null
}
// caller writes: sendNotification("Hello", "News") — clean금지: 컬렉션에서 Optional 사용하기
List, 집합 또는 맵 값 안에 Optional을 넣지 마십시오. 컬렉션에 비어 있는 Optional을 넣는 것은 의미가 없으므로 해당 항목을 생략하십시오.
// BAD: List of Optionals
List<Optional<User>> results = ...; // meaningless empty Optionals
// GOOD: List of present values only
List<User> presentUsers = maybeUsers.stream()
.flatMap(Optional::stream)
.collect(Collectors.toList());
// BAD: Map with Optional values
Map<String, Optional<String>> config = ...;
// GOOD: just use null or omit the key for absent values
Map<String, String> config2 = ...;
String value = config2.getOrDefault("key", "default");권장: 비용이 큰 기본값에는 orElseGet 사용하기
기본값을 계산해야 하는 경우(데이터베이스 쿼리, 네트워크 호출)에는 항상 orElseGet을 사용하십시오. supplier는 필요할 때만 호출됩니다.
import java.util.Optional;
// BAD: buildDefault() always called, even when value is present!
String config = getConfig("timeout").orElse(buildDefault());
// GOOD: supplier called lazily only when empty
String config2 = getConfig("timeout").orElseGet(() -> buildDefault());
// Or with method reference:
String config3 = getConfig("timeout").orElseGet(this::buildDefault);
// For cheap literals, orElse is fine
String name = getConfig("name").orElse("default");권장: 필수 값에는 orElseThrow 사용하기
값이 없는 것이 프로그래밍 오류 또는 불변 조건 위반이라면 설명적인 예외와 함께 orElseThrow를 사용하십시오.
import java.util.Optional;
// Good: throw when absence is an error
User user = userRepository.findById(userId)
.orElseThrow(() -> new UserNotFoundException("User not found: " + userId));
// Good: in validation code
String apiKey = Optional.ofNullable(System.getenv("API_KEY"))
.orElseThrow(() -> new IllegalStateException(
"API_KEY environment variable is required"));
System.out.println("Key found: " + apiKey.length() + " chars");안티패턴: isPresent + get()
isPresent()를 확인한 다음 get()을 호출하는 안티패턴을 피하십시오. 이는 null 확인보다 나을 것이 없으며 Optional의 목적을 무력화합니다.
import java.util.Optional;
Optional<String> opt = findValue();
// BAD: isPresent() + get() — no improvement over null check
if (opt.isPresent()) {
String val = opt.get();
process(val);
}
// GOOD: use the functional API
opt.ifPresent(this::process);
// GOOD: transform and return
return opt.map(this::process).orElse(null);
// GOOD: provide a default
String result = opt.orElse("default");연결에 관한 모범 사례
깔끔한 연결을 구성하십시오: find → filter → 변환 → fallback. 각 단계의 의미가 자체적으로 드러납니다.
import java.util.Optional;
record User(long id, String plan, boolean active) {}
static Optional<User> findUser(long id) { return Optional.empty(); }
String result = findUser(42L)
.filter(User::active) // keep only active users
.filter(u -> "PRO".equals(u.plan())) // keep only PRO users
.map(u -> "Welcome, Pro user #" + u.id()) // transform
.orElse("Upgrade to Pro!"); // fallback
System.out.println(result); // Upgrade to Pro!서비스 계층에서 Optional 사용하기
모범 사례를 따르는 실제와 유사한 서비스 계층 예제입니다.
import java.util.Optional;
class OrderService {
public Optional<OrderSummary> getOrderSummary(long orderId) {
return orderRepo.findById(orderId)
.filter(o -> !o.isCancelled())
.map(this::toSummary);
}
public OrderSummary requireOrderSummary(long orderId) {
return getOrderSummary(orderId)
.orElseThrow(() -> new OrderNotFoundException(orderId));
}
private OrderSummary toSummary(Order o) { return new OrderSummary(o); }
}
// API callers choose: Optional (handle absence) or require (exception)Optional과 null 안전성 도구
Optional은 완전한 null 안전성 적용을 위해 @Nullable/@NonNull 주석 및 SpotBugs/NullAway와 같은 도구를 보완합니다.
// Annotation-based: declares intent for in-class nulls
import org.jetbrains.annotations.*;
class ProductService {
@Nullable // may return null — for framework/bean use
public String getCachedName(String id) { return cache.get(id); }
// Optional — for service API that handles absence
public Optional<Product> findProduct(String id) {
return repo.findById(id);
}
}
// Use @Nullable for fields/parameters; Optional for return types빠른 확인
다음 코드의 문제는 무엇입니까?
if (opt.isPresent()) {
process(opt.get());
}복습: Optional 모범 사례
핵심 내용:
- Optional은 반환 형식으로만 사용하고, 필드나 메서드 매개변수로는 사용하지 마십시오
- 기본값을 계산하는 비용이 크다면 orElse보다 orElseGet을 선호하십시오
- 값의 부재가 프로그래밍 오류를 의미하면 orElseThrow를 사용하십시오
- isPresent() + get()을 피하고, 대신 ifPresent, map 또는 orElse를 사용하십시오
- 컬렉션 안에 Optional을 넣지 말고, 대신 스트림을 필터링하십시오
- 명확한 데이터 흐름을 위해 읽기 쉬운 연결을 구성하십시오: filter → map → orElse
자주 묻는 질문
“Optional 모범 사례” 강의는 무료인가요?
네 — “Optional 모범 사례” 전체 내용을 이 웹사이트에서 무료로 읽을 수 있습니다. 인터랙티브하게 실습하려면(내장 코드 에디터와 24/7 AI 튜터), CoddyKit PRO로 업그레이드하면 Java Academy 강의 전체를 잠금 해제할 수 있습니다. Java Academy 강의에는 총 4개의 강의가 포함되어 있습니다.
“Optional 모범 사례”에서 뭘 배우나요?
orElse, orElseGet, orElseThrow를 적용하고 Optional의 일반적인 안티 패턴을 피합니다. 브라우저에서 직접 실행하는 실습 코드로 Java Academy을(를) 배우며, 24/7 AI 튜터가 강의를 진행하면서 질문에 답변해줍니다.
Java Academy을(를) 시작하는 데 경험이 필요한가요?
사전 경험은 필요하지 않습니다. CoddyKit의 Java Academy은(는) 초급자부터 고급 학습자까지를 위해 구성되어 있으므로, 여기서 시작하거나 처음부터 시작할 수 있으며 자신의 속도대로 진행할 수 있습니다. 이것은 4개 중 4번째 강의입니다.
“Optional 모범 사례” 강의는 얼마나 걸리나요?
대부분의 CoddyKit 강의는 약 5~10분이 소요됩니다. 각 강의는 간결하고 인터랙티브하여 꾸준한 진행이 가능하며, 웹과 앱에서 중단한 부분부터 바로 시작할 수 있습니다.
이 Java Academy 강의에서 코드를 작성하고 실행할 수 있나요?
네. 모든 Java Academy 강의에는 내장 코드 에디터가 포함되어 있으므로, 브라우저에서 바로 실제 코드를 작성하고 실행한 후 즉시 AI 피드백을 받을 수 있습니다 — 로컬 설정이 필요 없습니다.