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 RuntimeExceptionmap(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 5filter(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