1. Optional이란
Optional
은 Java 8에서 도입된 클래스입니다. Optional
클래스는 값을 포함할 수 있거나 포함하지 않을 수 있는 컨테이너 객체입니다. 이 클래스의 주요 목적은 null
로 인해 발생하는 오류(예: NullPointerException
)를 방지하고, null
을 직접 사용하는 대신 보다 명확하고 안전한 방법으로 값의 존재 여부를 처리하는 것입니다.Optional의 기본 개념
- 값이 있을 수도 있고 없을 수도 있다:
Optional
은 값이 있을 때 그 값을 포함하고, 값이 없을 때는 비어 있는 컨테이너입니다. 이를 통해null
사용을 피하고,null
검사 없이 값의 유무를 명확히 처리할 수 있습니다.
- 의미 있는 반환값: 메서드가 실제 값 대신
Optional
을 반환하면, 그 메서드의 호출자는 반환된 값이 없을 경우를 명확히 처리해야 합니다. 이는 코드의 가독성을 높이고 오류를 줄이는 데 도움이 됩니다.
Optional 생성하기
Optional
객체를 생성하는 방법은 여러 가지가 있습니다:Optional.empty()
: 비어 있는Optional
을 생성합니다.
Optional<String> empty = Optional.empty();
Optional.of(value)
:null
이 아닌 값을 포함하는Optional
을 생성합니다. 값이null
이면NullPointerException
이 발생합니다.
Optional<String> opt = Optional.of("Hello");
Optional.ofNullable(value)
: 값이null
일 수 있는 경우 사용합니다. 값이null
이면 비어 있는Optional
을 반환하고, 그렇지 않으면 값을 포함하는Optional
을 반환합니다.
Optional<String> opt = Optional.ofNullable(null); // Returns Optional.empty()
Optional 사용하기
Optional
클래스에는 값을 처리하고 검사하는 다양한 메서드가 있습니다:isPresent()
:Optional
이 값을 포함하고 있는지 여부를 반환합니다.
Optional<String> opt = Optional.of("Hello");
if (opt.isPresent()) {
System.out.println(opt.get()); // "Hello"
}
ifPresent(Consumer<? super T> action)
:Optional
에 값이 있는 경우 지정된 동작을 실행합니다.
Optional<String> opt = Optional.of("Hello");
opt.ifPresent(value -> System.out.println(value)); // "Hello"
get()
:Optional
에 포함된 값을 반환합니다. 값이 없으면NoSuchElementException
이 발생합니다.
Optional<String> opt = Optional.of("Hello");
String value = opt.get(); // "Hello"
orElse(T other)
:Optional
이 비어 있는 경우 대체 값을 반환합니다.
Optional<String> opt = Optional.empty();
String value = opt.orElse("Default Value"); // "Default Value"
orElseGet(Supplier<? extends T> other)
:Optional
이 비어 있는 경우, 대체 값을 제공하는 함수를 실행하고 그 결과를 반환합니다.
Optional<String> opt = Optional.empty();
String value = opt.orElseGet(() -> "Generated Value"); // "Generated Value"
orElseThrow(Supplier<? extends X> exceptionSupplier)
:Optional
이 비어 있는 경우, 예외를 던집니다.
Optional<String> opt = Optional.empty();
String value = opt.orElseThrow(() -> new RuntimeException("Value is missing")); // Throws RuntimeException
map(Function<? super T, ? extends U> mapper)
:Optional
에 값이 있으면 값을 매핑하고, 새 값을 가진Optional
을 반환합니다.
Optional<String> opt = Optional.of("Hello");
Optional<Integer> lengthOpt = opt.map(String::length); // Optional containing 5
flatMap(Function<? super T, Optional<U>> mapper)
:Optional
에 값을 매핑하지만, 매핑 결과가 이미Optional
일 때 사용합니다.
Optional<String> opt = Optional.of("Hello");
Optional<Integer> lengthOpt = opt.flatMap(value -> Optional.of(value.length())); // Optional containing 5
filter(Predicate<? super T> predicate)
:Optional
의 값이 조건을 만족하는 경우, 그 값을 가진Optional
을 반환하고, 그렇지 않으면Optional.empty()
를 반환합니다.
Optional<String> opt = Optional.of("Hello");
Optional<String> filteredOpt = opt.filter(value -> value.startsWith("H")); // Optional containing "Hello"
Optional의 장점
null
안전성:null
사용을 줄이고,NullPointerException
발생 가능성을 줄입니다.
- 의미 있는 API 설계: 메서드의 반환 타입에
Optional
을 사용함으로써, 호출자에게 값의 유무에 대한 처리를 강제할 수 있습니다.
- 명확한 코드:
Optional
사용을 통해 코드의 의도를 명확히 할 수 있으며, 불필요한null
검사를 줄입니다.
Optional의 단점
- 불필요한 객체 생성:
Optional
은 객체이므로, 매우 많은 호출에서 사용하면 성능에 영향을 미칠 수 있습니다.
null
대체는 아님:Optional
을 사용하는 것이 무조건적인null
대체는 아닙니다. 특히 필드나 컬렉션에Optional
을 사용하는 것은 권장되지 않습니다.
Optional
은 값의 존재 여부를 안전하게 처리하고 명확한 코드를 작성하는 데 매우 유용한 도구입니다. 상황에 맞게 적절히 사용하여 코드의 가독성 및 안전성을 높일 수 있습니다.Optional 예제 코드 설명
이 코드는 Java에서
Optional
을 사용하여 null
값을 안전하게 처리하는 방법을 보여주는 테스트 메서드입니다. Optional
클래스는 Java 8에서 도입된 기능으로, null
로 인한 NullPointerException
을 방지하고 더 안전한 코드를 작성하는 데 도움이 됩니다. 각 부분을 설명해 드리겠습니다.@Test
public void go() {
User user = null;
Optional<User> op = Optional.ofNullable(user);
User user = null;
:user
변수를null
로 초기화합니다. 즉, 현재user
는 어떤User
객체도 참조하지 않고 있습니다.
Optional<User> op = Optional.ofNullable(user);
:user
변수를Optional
로 감쌉니다.Optional.ofNullable()
은user
가null
일 경우Optional.empty
를 반환하고, 그렇지 않으면Optional
에user
객체를 담아 반환합니다.
주석 처리된 코드 설명
1. 기본적인 값 가져오기
// User userPS = op.get();
// System.out.println(userPS.getId());
op.get()
:Optional
객체에서 값을 직접 꺼내는 메서드입니다.op
가 비어 있으면NoSuchElementException
을 던집니다.
- 이 코드에서는
user
가null
이기 때문에op.get()
을 호출하면 예외가 발생할 것입니다. 따라서 이 코드는 주석 처리되어 있습니다.
2. 값이 존재하는지 확인한 후 처리하기
// if(op.isPresent()){
// User userPS = op.get();
// }else{
// throw new RuntimeException("존재하지 않아요");
// }
op.isPresent()
:Optional
객체에 값이 있는지 확인합니다. 값이 있으면true
, 없으면false
를 반환합니다.
- 이 코드 블록은
op
에 값이 있으면 (isPresent()
가true
이면) 값을 꺼내와서userPS
에 저장하고, 그렇지 않으면 예외를 던집니다.
- 현재
user
가null
이므로op
는 비어 있고,isPresent()
는false
를 반환하여RuntimeException
이 발생합니다.
3. 값이 없을 경우 기본 값 제공
// User u = User.builder().id(1).username("ssar").build();
// User u2 = op.orElse(u);
// System.out.println(u2.getUsername());
User u = User.builder().id(1).username("ssar").build();
: 새로운User
객체를 빌더 패턴으로 생성합니다.id
가 1이고username
이"ssar"
인 객체를 만듭니다.
User u2 = op.orElse(u);
:op
가 비어 있으면u
를 반환하고, 그렇지 않으면op
에 담긴 객체를 반환합니다.
- 이 경우,
user
가null
이므로op
는 비어 있고,u2
는u
의 값을 가지게 됩니다.
System.out.println(u2.getUsername());
:u2
의username
을 출력합니다. 결과적으로"ssar"
가 출력됩니다.
4. 값이 없을 경우 예외 던지기
User u = op.orElseThrow(() -> new RuntimeException("fdsafdsafdsa"));
op.orElseThrow(() -> new RuntimeException("fdsafdsafdsa"));
:op
가 비어 있으면RuntimeException
을 던집니다. 람다식을 사용하여 예외를 생성합니다.
- 이 경우,
user
가null
이므로op
는 비어 있고, 예외가 발생합니다. 예외 메시지는"fdsafdsafdsa"
입니다.
전체 코드 요약
이 테스트 메서드는
Optional
을 사용하여 null
가능성을 처리하는 방법을 여러 가지 보여줍니다:- 값을 직접 가져오려고 시도할 수 있지만, 값이 없을 경우 예외가 발생할 수 있습니다.
- 값이 있는지 먼저 확인한 후에 안전하게 처리할 수 있습니다.
- 기본 값을 제공하여, 값이 없을 경우 기본 값을 사용할 수 있습니다.
- 값이 없을 경우 사용자 정의 예외를 던질 수 있습니다.
각 접근 방식은 상황에 따라 유용하게 사용할 수 있으며,
Optional
을 활용하면 null
처리를 보다 명확하고 안전하게 할 수 있습니다.Share article