티스토리 뷰
● 도입
- Optional을 이용해 해결할 수 있는 문제 = NPE(NullPointerException)
- Null 상태인 오브젝트를 레퍼런스 할 때 발생한다.
- Runtime error 이기 때문에 컴파일 과정에서는 발견할 수 없으며 실행 전 까지는 발생 여부를 알기 쉽지 않다.
- NullPointerException 발생 예시
[두 object가 같은지 비교해보자]
package com.fastcampus.functionalprogramming.chapter7;
import com.fastcampus.functionalprogramming.chapter7.model.User;
public class Chapter7Section1 {
public static void main(String[] args) {
// 일부러 NullPointerException을 발생시켜보자
User user1 = new User()
.setId(1001)
.setName("Alice")
.setVerified(false);
// user1은 setEmailAddress를 하지 않았다.
User user2 = new User()
.setId(1001)
.setName("Alice")
.setEmailAddress("alice@fastcampus.co.kr")
.setVerified(false);
// 정상
System.out.println(userEquals(user2, user1));
// NullPointerException 발생
System.out.println(userEquals(user1, user2));
}
public static boolean userEquals(User u1, User u2) {
return u1.getId() == u2.getId()
&& u1.getName().equals(u2.getName())
&& u1.getEmailAddress().equals(u2.getEmailAddress())
&& u1.isVerified() == u2.isVerified();
}
}
- 동일한 argument(user1, user2)를 넣었지만 단순히 순서를 바꾼 것만으로도 NullPointerException이 발생했다.
- null에 대한 체크를 사전에 제대로 하지 않았기 때문이다.
● Optional
- 이러한 문제를 해결하기 위해 필요한 것이 바로 Optional이다.
- Optional은 그 안에 Null 일수도 혹은 아닐 수도 있는 오브젝트를 담은 상자라고 생각하면 된다.
- 어떤 method의 return type이 Optional이라면 해당 return 값 안에 object가 있을 수도 or 없을 수도 있다고 예상할 수 있다.
java.util.Optional<T>
Optional<String> maybeString = Optional.of("Hello world");
String string = maybeString.get();
- String type의 Optional이 있을 때 maybeString 안에는 String instance가 있을 수도 있고 없을 수도 있다.
- get method를 통해 안에 있는 값을 꺼낼 수 있다.
[Optional 만드는 법]
public static <T> Optional<T> of(T value)
public static <T> Optional<T> empty()
public static <T> Optional<T> ofNullable(T value)
of
- Null이 아닌 오브젝트를 이용해 Optional을 만들 때
- 생성된 object instance가 이미 있을 때 해당 instance를 Optional 상자에 담을 때 사용
- Optional.of를 호출하고 Null을 넘기면 error 발생
Empty
- 빈 Optional을 만들 때
- 해당 type(= <T>)의 빈 상자를 만들 때
ofNullable
- Null인지 아닌지 알 지 못하는 오브젝트로 Optional을 만들 때
- Null이라면 알아서 빈 상자를 만들어준다.
- Null이 아니라면 해당 오브젝트가 들어있는 상자를 만들어준다.
[Optional 안에 있는 값을 확인하고 꺼내는 법]
public boolean isPresent()
public T get()
public T orElse(T other)
public T orElseGet(Supplier<? extends T> supplier)
public <X extends Throwable> T orElseThrow(Supplier<? extends X> exceptionSupplier) throws X
isPresent()
- Optional 안의 오브젝트가 null 인지 아닌지 체크(비어있는지 아닌지 체크)
- Null이 아닐 시 true(들어있으면 true)
get()
– Optional 안의 object를 추출
– Optional이 Null이면(비어있으면) 에러 발생
orElse(T other)
- 같은 타입의 object를 parameter로 받는다.
– Optional안에 object가 있다면(Optional이 null이 아니라면) Optional 안의 값을 return
- Optional안에 object가 null이라면(Optional이 비어있다면) parameter로 받은 other를 return
orElseGet(Supplier<? extends T> supplier)
- orElse와 다르게 return할 object를 바로 parameter로 받지 않는다.
- 대신 해당 type의 object를 받아 올 수 있는 supplier를 parameter로 받는다.
– Optional이 null이 아니라면 Optional 안의 값을, null이라면 supplier로 공급되는 값을 return
orElseThrow(Supplier<? extends X> exceptionSupplier)
- orElseGet와 비슷, 대신 exceptionSupplier를 parameter로 받는다.
– Optional이 null이 아니라면 Optional 안의 값을, null이라면 exceptionSupplier로 공급되는
exception을 던진다.
@FunctionalInterface
public interface Supplier<T> {
T get();
}
- input은 없고 output(return)만 있는 함수형 인터페이스
● 실습
package com.fastcampus.functionalprogramming.chapter7;
import java.util.Optional;
import com.fastcampus.functionalprogramming.chapter7.model.User;
public class Chapter7Section1 {
public static void main(String[] args) {
// ------------------ Optional 만들기 ------------------
String someEmail = "some@email.com";
String nullEmail = null;
// 1.
Optional<String> maybeEmail = Optional.of(someEmail);
// 2.
Optional<String> maybeEmail2 = Optional.empty(); // 빈 상자
// 3.
Optional<String> maybeEmail3 = Optional.ofNullable(someEmail); // null인지 아닌지 모르겠다.
// 4.
Optional<String> maybeEmail4 = Optional.ofNullable(nullEmail); // null인지 아닌지 모르겠다.
// ------------------ Optional 안에 있는 값 꺼내기 ------------------
// 1.
String email1 = maybeEmail.get();
System.out.println("email1 : " + email1);
// 2.
if(maybeEmail2.isPresent()) { // Optional 안에 값이 있는지 없는지 먼저 체크
System.out.println("email2 : " + maybeEmail2.get()); // maybeEmail2 Optional이 비어있기 때문에 해당 부분은 실행될 수 없다.
}
// 3.
String defaultEmail = "default@email.com";
String email3 = maybeEmail2.orElse(defaultEmail);
String email3_1 = maybeEmail.orElse(defaultEmail);
System.out.println("email3 : " + email3);
System.out.println("email3_1 : " + email3_1);
// 4.
String email4 = maybeEmail2.orElseGet(() -> defaultEmail);
String email4_1 = maybeEmail.orElseGet(() -> defaultEmail);
System.out.println("email4 : " + email4);
System.out.println("email4_1 : " + email4_1);
// 5.
String email5 = maybeEmail.orElseThrow(() -> new RuntimeException("email not present"));
System.out.println("email5 : " + email5);
String email5_1 = maybeEmail2.orElseThrow(() -> new RuntimeException("email not present"));
System.out.println("email5_1 : " + email5_1);
}
}
'Backend > Java8' 카테고리의 다른 글
#24 Advanced Stream - Max / Min / Count (0) | 2022.10.13 |
---|---|
#23 Optional 응용 method (0) | 2022.10.12 |
#21 Stream - flatMap(스트림의 스트림을 납작하게) (0) | 2022.10.10 |
#20 Stream - Distinct(중복 제거) (0) | 2022.10.09 |
#19 Stream - Sorted(데이터의 정렬) (0) | 2022.10.08 |
공지사항
최근에 올라온 글
최근에 달린 댓글
- Total
- Today
- Yesterday
링크
TAG
- 자료구조
- 프로세스
- jpa
- 코딩테스트
- 운영체제
- Phaser3
- java
- spring
- nosql
- git
- OS
- Spring Boot
- 메모리
- Java8
- 프로그래머스
- DART
- 알고리즘
- 빅데이터
- 빅데이터 분석기사
- MongoDB
- API
- db
- 코테
- Advanced Stream
- node.js
- SpringBoot
- Stream
- Phaser
- MySQL
- SQL
일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | 3 | 4 | 5 | 6 | 7 |
8 | 9 | 10 | 11 | 12 | 13 | 14 |
15 | 16 | 17 | 18 | 19 | 20 | 21 |
22 | 23 | 24 | 25 | 26 | 27 | 28 |
29 | 30 | 31 |
글 보관함