-
Java 8 - 4. Optional공부일기/Java 8 2020. 12. 22. 15:32

1. Optional이란?
비어있을 수도 있고, 뭔가를 담고 있을 수도 있는 컨테이너 인스턴스의 타입!
자바 프로그래밍에서 NullPointerException을 종종 보게 되는 이유
-
null을 리턴하니까! && null 체크를 깜빡했으니까!
메소드에서 작업 중 특별한 상황에서 값을 제대로 리턴할 수 없는 경우 선택할 수 있는 방법
-
예외를 던진다. (비싸다, 스택트레이스를 찍어두므로 예외를 던지는거 자체가 리소스에 영향을 줌.)
-
null을 리턴한다. (비용 문제가 없지만 그 코드를 사용하는 클라이언트 코드가 주의해야 한다.)
-
(자바 8부터) Optional을 리턴한다. (클라이언트에 코드에게 명시적으로 빈 값일 수도 있다는 걸 알려주고, 빈 값인 경우에 대한 처리를 강제한다.)
주의할 것
-
리턴값으로만 쓰기를 권장한다. (메소드 매개변수 타입, 맵의 키 타입, 인스턴스 필드 타입으로 쓰지 말자.)
-
Optional을 리턴하는 메소드에서 null을 리턴하지 말자.
-
프리미티브 타입용 Optional을 따로 있다. OptionalInt, OptionalLong,...
-
Collection, Map, Stream Array, Optional은 Opiontal로 감싸지 말 것.
2. Optional API
Optional 만들기
-
Optional.of()
-
Optional.ofNullable()
-
Optional.empty()
Optional에 값이 있는지 없는지 확인하기
-
isPresent()
package optional; import java.util.Arrays; import java.util.List; import java.util.Optional; public class practice { public static void main(String[] args) { List<Integer> numbers = Arrays.asList(1,3,5,10,15,20); Optional<Integer> optional = numbers.stream() .filter(number -> number.equals(5)) .findFirst(); if (optional.isPresent()){ Integer five = optional.get(); System.out.println(five); } } }5-
isEmpty() (Java 11부터 제공)
package optional; import java.util.Arrays; import java.util.List; import java.util.Optional; public class practice { public static void main(String[] args) { List<Integer> numbers = Arrays.asList(1,3,5,10,15,20); Optional<Integer> emptyOptional = numbers.stream() .filter(number -> number.equals(13)) .findFirst(); if (emptyOptional.isEmpty()) { System.out.println("nothing"); } } }nothingOptional에 있는 값 가져오기
-
get()
package optional; import java.util.Arrays; import java.util.List; import java.util.Optional; public class practice { public static void main(String[] args) { List<Integer> numbers = Arrays.asList(1,3,5,10,15,20); Optional<Integer> optional = numbers.stream() .filter(number -> number.equals(5)) .findFirst(); if (optional.isPresent()){ Integer five = optional.get(); System.out.println(five); } } }위에서 사용한 예제와 동일하다.
-
만약에 비어있는 Optional에서 무언가를 꺼낸다면??
인텔리제이에서 get()을 호출하기 전에 값이 존재하는지 확인 후에 꺼낼 것을 권장한다. NoSuchElementException이 발생하기 위해 if문을 이용하거나 아래 나와있는 API를 활용할 수 있다.
Optional에 값이 있는 경우에 그 값을 가지고 ~~를 하라.
-
ifPresent(Consumer)
package optional; import java.util.Arrays; import java.util.List; import java.util.Optional; public class practice { public static void main(String[] args) { List<Integer> numbers = Arrays.asList(1,3,5,10,15,20); Optional<Integer> optional = numbers.stream() .filter(number -> number % 2 == 0) .findFirst(); optional.ifPresent(even -> System.out.println(even)); } }10-
예) Spring으로 시작하는 수업이 있으면 id를 출력하라.
package optional; import java.util.ArrayList; import java.util.List; import java.util.Optional; public class practice { public static void main(String[] args) { List<OnlineClass> springClasses = new ArrayList<>(); springClasses.add(new OnlineClass(1, "spring boot", true)); springClasses.add(new OnlineClass(5, "rest api development", false)); Optional<OnlineClass> optional = springClasses.stream() .filter(oc -> oc.getTitle().startsWith("spring")) .findFirst(); optional.ifPresent(oc -> System.out.println(oc.getId())); } }1Optional에 값이 있으면 가져오고 없는 경우에 ~~를 리턴하라.
-
orElse(T)
package optional; import java.util.ArrayList; import java.util.List; import java.util.Optional; public class practice { public static void main(String[] args) { List<OnlineClass> springClasses = new ArrayList<>(); springClasses.add(new OnlineClass(1, "spring boot", true)); springClasses.add(new OnlineClass(5, "rest api development", false)); Optional<OnlineClass> optional = springClasses.stream() .filter(oc -> oc.getTitle().startsWith("jpa")) .findFirst(); OnlineClass onlineClass = optional.orElse(createNewClass()); System.out.println(onlineClass.getTitle()); } private static OnlineClass createNewClass() { return new OnlineClass(3, "New jpa", false); } }New jpa위 예제의 경우 startsWith("jpa")가 아닌 startsWith("spring"), 즉 spring 수업이 있는 경우에도 orElse를 실행하고 새로운 수업이 만들어진다. 이런 경우 orElseGet을 이용하면 된다.
이미 만들어져있는 인스턴스를 참고해서 사용하는 경우 사용하기 적합하다.
Optional에 값이 있으면 가져오고 없는 경우에 ~~를 하라.
-
orElseGet(Supplier)
package optional; import java.util.ArrayList; import java.util.List; import java.util.Optional; public class practice { public static void main(String[] args) { List<OnlineClass> springClasses = new ArrayList<>(); springClasses.add(new OnlineClass(1, "spring boot", true)); springClasses.add(new OnlineClass(5, "rest api development", false)); Optional<OnlineClass> optional = springClasses.stream() .filter(oc -> oc.getTitle().startsWith("jpa")) .findFirst(); OnlineClass onlineClass = optional.orElseGet(practice::createNewClass); System.out.println(onlineClass.getTitle()); } private static OnlineClass createNewClass() { System.out.println("CREATING NEW ONLINE CLASS"); return new OnlineClass(3, "NEW CLASS", false); } }CREATING NEW ONLINE CLASS NEW CLASS동적으로 추가 작업이 필요한 경우 orElseGet을 사용하는게 적절하다.
-
예) JPA로 시작하는 수업이 없다면 새로 만들어서 리턴하라.
package optional; import java.util.ArrayList; import java.util.List; import java.util.Optional; public class practice { public static void main(String[] args) { List<OnlineClass> springClasses = new ArrayList<>(); springClasses.add(new OnlineClass(1, "spring boot", true)); springClasses.add(new OnlineClass(5, "rest api development", false)); Optional<OnlineClass> optional = springClasses.stream() .filter(oc -> oc.getTitle().startsWith("jpa")) .findFirst(); OnlineClass onlineClass = optional.orElseGet(practice::createNewClass); System.out.println(onlineClass.getTitle()); } private static OnlineClass createNewClass() { System.out.println("CREATING NEW ONLINE CLASS"); return new OnlineClass(3, "NEW CLASS", false); } }CREATING NEW ONLINE CLASS NEW CLASS위 예제와 동일하다.
이미 만들어져있는 인스턴스를 참고해서
Optional에 값이 있으면 가져오고 없는 경우 에러를 던져라.
-
orElseThrow()
package optional; import java.util.ArrayList; import java.util.List; import java.util.Optional; public class practice { public static void main(String[] args) { List<OnlineClass> springClasses = new ArrayList<>(); springClasses.add(new OnlineClass(1, "spring boot", true)); springClasses.add(new OnlineClass(5, "rest api development", false)); Optional<OnlineClass> optional = springClasses.stream() .filter(oc -> oc.getTitle().startsWith("jpa")) .findFirst(); OnlineClass onlineClass = optional.orElseThrow(() -> { return new IllegalStateException("없습니다."); }); System.out.println(onlineClass.getTitle()); } private static OnlineClass createNewClass() { System.out.println("creating new online class"); return new OnlineClass(3, "New class", false); } }
대체할 게 없는 경우 에러를 던지도록 만들 수 있다.
Optional에 들어있는 값 걸러내기
-
Optional filter(Predicate)
package optional; import java.util.ArrayList; import java.util.List; import java.util.Optional; public class practice { public static void main(String[] args) { List<OnlineClass> springClasses = new ArrayList<>(); springClasses.add(new OnlineClass(1, "spring boot", true)); springClasses.add(new OnlineClass(5, "rest api development", false)); Optional<OnlineClass> optional = springClasses.stream() .filter(oc -> oc.getTitle().startsWith("spring")) .findFirst(); Optional<OnlineClass> onlineClass = optional.filter(oc -> oc.isClosed()); System.out.println(onlineClass.isPresent()); } }truespring으로 시작하는 optional 중에 isClosed()가 true인 값들을 걸러내고, isPresent()를 통해 존재하는 경우 true 출력, 존재하지 않는 경우 false를 출력하는 코드.
있다는 가정하에 동작하며 없는 경우 아무일도 일어나지 않는다.
Optional에 들어있는 값 변환하기
-
Optional map(Function)
package optional; import java.util.ArrayList; import java.util.List; import java.util.Optional; public class practice { public static void main(String[] args) { List<OnlineClass> springClasses = new ArrayList<>(); springClasses.add(new OnlineClass(1, "spring boot", true)); springClasses.add(new OnlineClass(5, "rest api development", false)); Optional<OnlineClass> optional = springClasses.stream() .filter(oc -> oc.getTitle().startsWith("spring")) .findFirst(); Optional<Integer> integer = optional.map(oc -> oc.getId()); System.out.println(integer.isPresent()); } }true-
Optional flatMap(Function): Optional 안에 들어있는 인스턴스가 Optional인 경우에 사용하면 편리하다.
flatMap을 사용하는 경우 return 되는 타입이 optional인 경우 한 번 더 박스에서 꺼내 해당 타입을 반환한다.
'공부일기 > Java 8' 카테고리의 다른 글
Java 8 - 6. Concurrent 프로그래밍과 Executors (0) 2020.12.24 Java 8 - 5. Date & Time (0) 2020.12.23 Java 8 - 3. Stream (0) 2020.12.16 Java 8 - 2. 인터페이스의 변화 (0) 2020.12.07 Java 8 - 1. 함수형 인터페이스와 람다 표현식 (0) 2020.12.06 -