Optional
Optional은 어떤 객체를 wrapping하는 객체입니다. 즉, 어떤 객체를 포함할 수 있고 또는 null 객체를 포함할 수 있습니다. 자바의 null 처리를 유연하게 하고자 도입된 것 같습니다.
아래 코드는 Optional<String>
객체를 생성하고 내부의 String 객체를 출력하는 예제입니다.
Optional 객체는 단순히 내부에 String 객체를 감싸는 wrapper 객체입니다.
내부의 객체를 사용하려면 opString.get()
처럼 get()
이 내부 객체를 리턴합니다.
Optional은 Optional.of()
에 객체를 넣어 생성할 수 있습니다
String string = "a string in optional";
Optional<String> opString = Optional.of(string);
System.out.println(opString.get());
결과
a string in optional
만약 null을 wrapping하는 Optional 객체를 만드려면 어떻게 해야 할까요?
Optional.of(null)
은 허용되지 않습니다. Optional.of()
는 null이 아닌 객체만 사용할 수 있습니다.
반면에 Optional.ofNullable()
은 객체 생성 시 null을 허용합니다. 이를 이용하면 null을 포함하는 Optional 객체를 만들 수 있습니다.
아래 코드를 실행해보면 nullOpString.get()
는 null이기 때문에 NoSuchElementException 예외가 발생됩니다.
String nullString = null;
Optional<String> nullOpString = Optional.ofNullable(nullString);
try {
System.out.println(nullOpString.get());
} catch (NoSuchElementException e) {
System.out.println("No such element");
}
결과
No such element
다른 방법으로, Optional.empty()
는 null을 포함하는 Optional 객체를 생성합니다.
역시 emptyOptional.get()
는 null이기 때문에 NoSuchElementException 예외가 발생합니다.
Optional<String> emptyOptional = Optional.empty();
try {
System.out.println(emptyOptional.get());
} catch (NoSuchElementException e) {
System.out.println("No such element");
}
결과
No such element
isPresent()
예외가 발생하지 않으려면 null인지 미리 체크하고 사용해야 합니다. isPresent()
는 내부 객체가 null인지 알려줍니다.
아래 코드에서 opString만 null이 아니기 때문에 출력이 됩니다.
Optional<String> opString = Optional.of("a string in optional");
Optional<String> nullOpString = Optional.ofNullable(nullString);
if (opString.isPresent()) {
System.out.println("opString: " + opString.get());
}
if (nullOpString.isPresent()) {
System.out.println("nullOpString: " + nullOpString.get());
}
결과
opString: a string in optional
위의 코드는 기존의 자바스타일과 유사합니다. if (opString != null)
처럼 if를 사용하기 때문입니다.
이번에는 동일 동작을 위와 다른 스타일로 표현하겠습니다. void ifPresent(Consumer)
는 객체가 null이 아니면 param으로 넘겨준 Consumer 함수를 호출합니다. null인 경우 아무것도 하지 않습니다.
아래 코드에서 nullOpString의 내부 객체는 null이기 때문에 아무것도 출력하지 않습니다. 반대로 opString는 null이 아니기 때문에 param을 넘겨준 함수가 호출되었습니다.
Optional<String> opString = Optional.of("a string in optional");
Optional<String> nullOpString = Optional.ofNullable(nullString);
opString.ifPresent(s -> System.out.println("opString: " + s));
nullOpString.ifPresent(s -> System.out.println("nullOpString: " + s));
결과
opString: a string in optional
orElse
위의 코드는 Optional 객체가 null인 경우 아무것도 호출하지 않았습니다.
만약 null일 때 다른 값을 갖도록 설정할 수 없을까요?
orElse(object)
가 이런 일을 처리할 수 있습니다. 만약 Optional이 null인 경우 orElse()의 param이 리턴됩니다.
아래 코드에서 nullOpString은 null이기 때문에 str2는 "new string from orElse"
으로 설정됩니다.
Optional<String> opString = Optional.of("a string in optional");
Optional<String> nullOpString = Optional.ofNullable(nullString);
String str = opString.orElse("new string from orElse");
System.out.println(str);
String str2 = nullOpString.orElse("new string from orElse");
System.out.println(str2);
결과
a string in optional
new string from orElse
orElseGet
만약 Optional이 null인 경우 어떤 함수를 실행하고 그 실행결과를 대입하고 싶을 수 있습니다.
이런 일은 orElseGet(Supplier)
가 할 수 있습니다. Supplier는 함수로, 람다 표현식을 사용하면 됩니다.
아래 코드에서 nullOpString는 null을 포함하기 때문에 str4는 "new string from orElseGet"
로 설정됩니다.
Optional<String> opString = Optional.of("a string in optional");
Optional<String> nullOpString = Optional.ofNullable(nullString);
String str3 = opString.orElseGet(() -> "new string from orElseGet");
System.out.println(str3);
String str4 = nullOpString.orElseGet(() -> "new string from orElseGet");
System.out.println(str4);
결과
a string in optional
new string from orElseGet
orElseThrow
Optional이 null인 경우 예외를 던지고 싶을 수 있습니다. 이런 일은 orElseThrow()
가 할 수 있습니다.
Optional이 참조하는 객체가 null인 경우 예외를 던집니다.
아래 코드에서 nullOpString는 null이기 때문에 NullPointerException를 던집니다.
Optional<String> opString = Optional.of("a string in optional");
Optional<String> nullOpString = Optional.ofNullable(nullString);
try {
String str5 = opString.orElseThrow(NullPointerException::new);
System.out.println(str5);
} catch (NullPointerException e) {
System.out.println("NullPointerException");
}
try {
String str6 = nullOpString.orElseThrow(NullPointerException::new);
System.out.println(str6);
} catch (NullPointerException e) {
System.out.println("NullPointerException");
}
결과
a string in optional
NullPointerException
filter
이번에는 Optional.filter(Predicate)
를 알아보겠습니다.
Optional은 내부에 1개의 아이템만 갖고 있어 filter라는 것이 의미상 어색할 수 있습니다. Optional 객체에 filter를 사용하면,
Optional의 내부 객체가 Predicate 조건에 부합하면 이 객체를 포함한 Optional 객체가 리턴됩니다.
그렇지 않으면 Empty optional 객체가 리턴됩니다.
아래 코드를 보시면, opStr2는 first를 포함하고 있지 않기 때문에 Empty optional 객체가 리턴됩니다. 따라서 filtered2는 Empty이므로 아무것도 출력이 되지 않습니다.
Optional<String> opStr1 = Optional.of("first string");
Optional<String> opStr2 = Optional.of("second string");
Optional<String> filtered1 = opStr1.filter(s -> s.contains("first"));
Optional<String> filtered2 = opStr2.filter(s -> s.contains("first"));
filtered1.ifPresent(System.out::println);
filtered2.ifPresent(System.out::println);
참고
Related Posts
- Java - 람다식(Lambda)과 함수형 인터페이스
- Java - 직렬화(Serialize), 역직렬화(Deserialize)
- Java - do while과 while의 차이점
- Java - List empty(null) 체크, 3가지 방법
- Java - ArrayList 초기화, 4가지 방법
- Java - HashSet.addAll()
- Java - HashSet.contains()
- Java - 2차원 배열 선언, 출력 방법
- Java - 리스트 정렬, 3가지 방법
- Java - HashSet 정렬, 3가지 방법
- Java - 리스트 (List, ArrayList)
- Java - 첫 글자만 대문자로 바꾸는 방법
- Java - hashCode(), 사용하는 이유? 구현 방법?
- Java8의 Stream reduce() 사용 방법 및 예제
- Java - filter, map, flatMap 사용 방법 및 예제
- Java - 2개의 Map 합치기 (merge, putAll)
- Java - ConcurrentModificationException 원인 및 해결 방법
- JUnit - @After와 @AfterClass의 차이점
- JUnit - @Before와 @BeforeClass의 차이점
- java와 javac의 차이점
- Java - 자바(JDK) 버전 확인 방법 (터미널, cmd 명령어)
- Java - java.util.Date를 java.sql.Date로 변환
- Java - 시스템 운영체제(OS) 정보 확인
- Java - 코드 실행 시간 측정
- Java - HashSet.retainAll() 사용 방법 및 예제
- Java - ArrayList.retainAll() 사용 방법 및 예제
- Java - ArrayList를 String으로 변환
- Java - float을 int로 변환
- Java - float을 String으로 변환
- Java - String을 boolean으로 변환
- Java - XML을 JSON으로 변환
- Java - ClassNotFoundException 발생 원인 및 해결 방법
- Java - private 생성자를 사용하는 이유
- Java - non-static method cannot be referenced from a static context
- Java - NoSuchMethodError 원인 및 해결 방법