자바 옵셔널(Optional) 개요
Java 8부터 도입된 Optional
은 null을 직접 다루는 것을 피하고자하는 목적으로 만들어진 래퍼 클래스입니다. Optional
을 사용하면 null 체크를 명시적으로 하지 않아도 되므로 NullPointerException을 방지할 수 있습니다.
Optional<String> optional = Optional.of("Hello, World!");
옵셔널 생성
Optional
인스턴스는 Optional.empty()
, Optional.of(value)
, Optional.ofNullable(value)
세 가지 메소드를 통해 생성할 수 있습니다.
Optional.empty()
: 빈Optional
객체를 생성합니다.
Optional.of(value)
: 주어진 값이 null이 아닌 경우,Optional
객체를 생성합니다. 만약 null이 주어지면 NullPointerException이 발생합니다.
Optional.ofNullable(value)
: 주어진 값이 null인지 아닌지 모를 경우,Optional
객체를 생성합니다. 값이 null인 경우 빈Optional
객체를 반환합니다.
Optional<String> emptyOptional = Optional.empty();
Optional<String> nonNullOptional = Optional.of("Hello, World!");
Optional<String> nullableOptional = Optional.ofNullable(null);
옵셔널 값 사용
Optional
에 저장된 값은 get()
, orElse(defaultValue)
, orElseGet(supplier)
등의 메소드를 통해 가져올 수 있습니다.
get()
:Optional
에 저장된 값을 가져옵니다. 값이 존재하지 않는 경우 NoSuchElementException이 발생합니다.
orElse(defaultValue)
:Optional
에 저장된 값을 가져옵니다. 값이 존재하지 않는 경우 defaultValue를 반환합니다.
orElseGet(supplier)
:Optional
에 저장된 값을 가져옵니다. 값이 존재하지 않는 경우 supplier가 제공하는 값을 반환합니다.
isPresent()
메소드는Optional
인스턴스가 값을 포함하고 있는지를 확인하는 메소드입니다. 값이 존재하면 true를 반환하고, 값이 존재하지 않으면 false를 반환합니다.
Optional<String> optional = Optional.of("Hello, World!");
System.out.println(optional.get()); // 출력: Hello, World!
optional = Optional.empty();
System.out.println(optional.orElse("Default Value")); // 출력: Default Value
optional = Optional.empty();
System.out.println(optional.orElseGet(() -> "Generated Value")); // 출력: Generated Value
Optional<String> optional = Optional.of("Hello, World!");
System.out.println(optional.isPresent()); // 출력: true
optional = Optional.empty();
System.out.println(optional.isPresent()); // 출력: false
옵셔널 활용
Optional
은 주로 메소드의 반환 값이 null일 수도 있는 경우, null 대신 Optional
을 반환하도록 사용합니다. 이렇게 하면 메소드를 호출하는 측에서는 반환 값이 null인지 아닌지를 체크하지 않아도 되므로 코드의 가독성을 향상시킬 수 있습니다.
public Optional<String> findUserById(String id) {
// 사용자를 찾는 로직
// 사용자를 찾지 못한 경우 Optional.empty()를 반환
return Optional.empty();
}
Optional<String> user = findUserById("1234");
if (user.isPresent())
System.out.println(user.get());
else
System.out.println("사용자를 찾지 못했습니다.");
이처럼 Optional
은 null을 직접 다루는 것을 피하고자 할 때, 특히 메소드의 반환 값이 null일 수도 있는 경우에 유용하게 사용할 수 있습니다.
orElseGet() 메소드와 Supplier
orElseGet()
메소드는 Optional
인스턴스가 값을 포함하고 있으면 그 값을 반환하고, 값이 존재하지 않으면 Supplier
인터페이스를 통해 제공된 값을 반환합니다.
Supplier
인터페이스는 Java 8부터 도입된 함수형 인터페이스로, 입력값은 없고 반환값만 있는 함수를 정의할 때 사용됩니다. orElseGet()
메소드에서는 Supplier
를 통해 Optional
의 값이 없을 때 대신 반환할 값을 정의합니다.
Optional<String> optional = Optional.of("Hello, World!");
System.out.println(optional.orElseGet(() -> "Default Value")); // 출력: Hello, World!
optional = Optional.empty();
System.out.println(optional.orElseGet(() -> "Default Value")); // 출력: Default Value
위 코드에서 () -> "Default Value"
부분이 Supplier
인터페이스를 구현한 람다 표현식입니다. 이 람다 표현식은 입력값 없이 "Default Value"라는 문자열을 반환하는 함수를 정의하고 있습니다. 따라서 orElseGet()
메소드는 Optional
의 값이 존재하지 않을 때 "Default Value"를 반환하게 됩니다.
주의 및 참고
Optional 객체 생성 최소화
Optional
객체는 필요할 때만 생성하는 것이 좋다. Optional
객체를 불필요하게 생성하면 메모리 사용량이 증가하고, 성능이 저하될 수 있다. 따라서 메소드에서 Optional
을 반환할 때는 가능한 빈 Optional
을 재사용하는 것이 좋다.
// 좋은 예
public Optional<String> getOptionalGood() {
return Optional.empty();
}
// 나쁜 예
public Optional<String> getOptionalBad() {
return Optional.ofNullable(null);
}
Optional 반환값의 null 체크
Optional
을 반환하는 메소드를 호출한 후, 반환값을 null로 체크하지 않도록 주의해야 한다. Optional
을 반환하는 메소드는 null 대신 빈 Optional
을 반환하므로, 반환값의 null 체크는 불필요! Optional
의 isPresent()
, isEmpty()
, orElse()
, orElseGet()
등의 메소드를 사용하여 Optional
의 값을 안전하게 처리하는게 좋다 !
// 좋은 예
Optional<String> optional = getOptional();
if (optional.isPresent()) {
System.out.println(optional.get());
}
// 나쁜 예
Optional<String> optional = getOptional();
if (optional != null) {
System.out.println(optional.get());
}
Optional의 get() 메소드 사용 주의
Optional
의 get()
메소드는 Optional
에 값이 존재할 때만 사용해야 한다. 값이 존재하지 않는데 get()
메소드를 호출하면 NoSuchElementException 발생. get()
메소드를 호출하기 전에 항상 isPresent()
메소드를 사용하여 값의 존재 여부를 확인하거나, orElse()
, orElseGet()
등의 메소드를 사용하여 값이 없을 때의 대체 값을 지정하는 것이 좋다.
// 좋은 예
Optional<String> optional = getOptional();
if (optional.isPresent()) {
System.out.println(optional.get());
}
// 나쁜 예
Optional<String> optional = getOptional();
System.out.println(optional.get());
Optional
의 이점을 최대한 활용하여 사용하자!
참고 블로그