[java] Optional 사용 By starseat 2022-10-17 12:31:56 java/spring Post Tags # Optional - java 8 에 추가 - 있거나 없는 값 표현 - null 대체 ## 생성 - `Optional.of()`: null 이 아닌 값 ```java Optional opt = Optional.of("value"); Optional.of(null) -> NullPointerException ! ``` - `Optional.ofNullable()`: null이 가능한 값으로 생성 ```java Optional opt = Optional.ofNullable(someValue); ``` - `Optional.empty()`: 빈 값 ```java Optional opt1 = Optional.empty(); Optional opt2 = Optional.ofNullable(null); ``` ## 조회 - get() - 값이 없는 Optional에 get() 을 실행하면 `NoSuchElementException` 발생 ```java Optional opt = Optional.of("value"); String str = opt.gt(); // str: "value" Optional opt1 = Optional.empty(); opt1.get(); // NoSuchElementException ``` ## 값 존재 확인 - `isPresent()`: 값이 있는지 확인 - `isEmpty()`: 값이 비었는지 확인 (java 11) ```java Optional opt = Optional.of("value"); opt.isPresent(); // true opt.isEmpty(); // false Optional opt1 = Optional.empty(); opt`.isPresent(); // false opt`.isEmpty(); // true ``` ## 값이 있으면 실행 - `ifPresent()` : if 문 ```java String value1 = getValue1(); if (value1 != null) { doSome(value); } // change.. Optional opt1 = getValue(); opt1.ifPresent(value1 -> doSome(value1)); ``` - `ifPresentOrElse()`: if-else 문 ```java String value2 = getValue(); if (value2 != null) { doSome(value2); } else { doOther(); } // change.. Optional opt2 = getValue(); opt2.ifPresentOrElse( value2 -> doSome(value2), () -> doOther() ); ``` ## 값이 없을 때 다른 값 사용 ```java String value = getValue(); String result = value == null ? "default" : value; ``` - `orElse()` - 값이 있으면 그 값을 return - 값이 없으면 인자로 전달한 값 전달 (아래 예제에선 `default` return) ```java Optional opt = getValue(); String result = opt.orElse("default"); // String result = opt.orElse(null); ``` - `orElseGet()` - `orElase` 와 거의 동일하나 값일 없을 경우 값 대신에 실행할 `method` 를 지정 ```java Optional opt = getValue(); // orElseGet(Supplier extends T>) String result = opt.orElseGet(() -> "default"); ``` - `or()` - 값이 없을 경우 사용할 `Optional` return ```java Optional opt = getValue(); // or(Supplier extends Optional extends T>>) Optional result = opt.or(() -> Optional.or("default")); ``` - `orElseThrow` - 값이 있으면 해당 값 return, 없으면 `exception` 발생 ```java Member m = repository.findById("id"); if ( m == null) { throw new NoMemberException(); } m.doSomething(); // change.. Optional opt = repository.findByid("id"); Member m = opt.orElseThrow(() -> new NoMemberException()); m.doSomething(); ``` ## map - `map`에 전달 받은 함수를 실행해서 값을 변환한 `Optional` return - `map`은 값이 없으면 빈 `Optional` return ```java Member m = repository.findById("id"); LocalDate birth = m.getBirthday(); int passedDays = cal(birth); // change... Optional memOpt = repository.findByid("id"); Optional birthOpt = memOpt.map(mem -> mem.getBirthday()); Optional pdOpt = birthOpt.map(birth -> cal(birth)); // 한번에 변환 Optional pdOpt2 = memOpt.map(mem -> mem.getBirthday()).map(birth -> cal(birth)); // 빈 Optionaal 은 map 으로 전달한 함수를 실행하지 않고 빈 Optional 리턴 Optional empty = Optional.empty(); Optional empty2 = empty.map(str -> str.toUpperCase()); // empty2.isEmpty() -> true ``` ## flatMap - `flatMap`에 전달 받은 함수 이용 값을 변환한 `Optional` return - `flatMap`에 전달한 함수는 `return type` 이 `Optional` ```java // Optional flatMap(Function super T, ? extends Optional extends U>> mapper) Optional memOpt = repository.findByid("id"); Optional birthOpt = memOpt.flatMap(mem -> Optional.orNullable(mem.getBirthday())); Optional pdOpt = birthOpt.flatMap(birth -> calOptional> 와 같은 자료형의 Optional 을 하나 뺴주는 역할. ``` ## filter - 조건을 충족하면 값 그대로 return - 조건을 충족하지 못하면 빈 `Optional` return ```java String str = getStringValue(); if (str != null && str.length() > 3) { System.out.println("str: " + str); } // change 1 Optional strOpt1 = getStringValue(); Optional filtered1 = strOpt.filter(str -> str.length() > 3); filtered1.isPresent(str -> System.out.println("str1: " + str)); // change 2 Optional strOpt2 = getStringValue(); Optional filtered2 = strOpt .filter(str -> str.length() > 3) .ifPresent(str -> System.out.println("str2: " + str2)); ``` ## 두 개의 Optional 조합 - 예제 소스 ```java Member m = repository.findByid("id"); if (m == null) { return null; } Company c = getCompany(m); if (c == null) { return null; } Card card = createCard(m, c); return card; ``` - 변환 1 ```java Optional memOpt = repository.findByid("id"); Optional comOpt = memOpt.map(mem -> getCompaany(mem)); Optional card = memOpt.flatMap( mem -> comOpt.map(com -> createCard(mem, com); ); ``` - 변환 2 ```java Optional memOpt = repository.findByid("id"); Optional cardOpt = memOpt.flatMap(mem -> { Optional comOpt = getCompanyOptional(mem)); return comOpt.map(com -> createCard(mem, com)); }); ``` # 정리 - `isPresent()` 사용하면 -> null 사용할 때 유사한 구조 - 대신 `map`, `flatMap`, `filter`, `orElse`, `or`, `ifPresent` 등 익숙해지기 - `Optional`을 조금 더 `Optional` 답게 # 출처 & 참고 - 최범균 님의 [[youtube 초식 - 자바 Optional 기초]](https://www.youtube.com/watch?v=RsUTolCVm_E) - [Optional 제대로 활용하기](https://www.latera.kr/blog/2019-07-02-effective-optional/#2-optional-get-%ED%98%B8%EC%B6%9C-%EC%A0%84%EC%97%90-optional-%EA%B0%9D%EC%B2%B4%EA%B0%80-%EA%B0%92%EC%9D%84-%EA%B0%80%EC%A7%80%EA%B3%A0-%EC%9E%88%EC%9D%8C%EC%9D%84-%ED%99%95%EC%8B%A4%ED%9E%88-%ED%95%A0-%EA%B2%83) Previous Post [spring] @Bean 선택적 사용 Next Post [jpa] JPA annotation