🐰JAVA/Basic

[ JAVA ] Optional

🐢 개발개발 🐾 2022. 6. 15. 11:23

Optional μ΄λž€? 

κ°œλ°œμ„ ν•  λ•Œ κ°€μž₯ 많이 λ°œμƒν•˜λŠ” μ˜ˆμ™Έ 쀑 ν•˜λ‚˜λŠ” λ°”λ‘œ  NullPointerException μž…λ‹ˆλ‹€. NullPointerException 을 ν”Όν•˜κ³  null μ²΄ν¬ν•˜λŠ” λ‘œμ§μ„ 쀄이기 μœ„ν•΄ 빈 값일 λ•Œ null λŒ€μ‹  μ΄ˆκΈ°κ°’μ„ μ‚¬μš©ν•˜κΈΈ ꢌμž₯ν•˜κ³€ ν•©λ‹ˆλ‹€.

List<String> names = getNames();
names.sort(); // names κ°€ null 이라면 NullPointerException 이 μΌμ–΄λ‚œλ‹€.

μžλ°” 8μ—μ„œλŠ” Optional<T> ν΄λž˜μŠ€λ₯Ό μ΄μš©ν•΄μ„œ NullPointerException 을 λ°©μ§€ν•  수 μžˆμŠ΅λ‹ˆλ‹€.

즉, λ³΅μž‘ν•œ 쑰건문 없이도 널(null) κ°’μœΌλ‘œ 인해 λ°œμƒν•˜λŠ” μ˜ˆμ™Έλ₯Ό μ²˜λ¦¬ν•  수 있게 λ©λ‹ˆλ‹€.

public final class Optional<T> {

  // If non-null, the value; if null, indicates no value is present
  private final T value;
  
  ...
}

value μ— 값을 μ €μž₯ν•˜κΈ° λ•Œλ¬Έμ— 값이 null μ΄λ”라도 λ°”λ‘œ μ°Έμ‘° μ‹œ NullPointerException κ°€ λ‚˜μ§€ μ•Šκ³ , 클래슀이기 λ•Œλ¬Έμ— 각쒅 λ©”μ†Œλ“œλ₯Ό μ œκ³΅ν•΄μ€λ‹ˆλ‹€.

 

Optional<T> 클래슀

Integerλ‚˜ Double 클래슀처럼 'T'νƒ€μž…μ˜ 객체λ₯Ό 포μž₯ν•΄ μ£ΌλŠ” 래퍼 클래슀(Wrapper class)μž…λ‹ˆλ‹€. λ”°λΌμ„œ Optional μΈμŠ€ν„΄μŠ€λŠ” λͺ¨λ“  νƒ€μž…μ˜ μ°Έμ‘° λ³€μˆ˜λ₯Ό μ €μž₯ν•  수 μžˆμŠ΅λ‹ˆλ‹€.

Optional 객체의 생성

1. Optional.empty() 빈 객체 생성 

Optional<String> optional = Optional.empty();
System.out.println(optional); // Optional.empty

System.out.println(optional.isPresent()); // false

 

2. of() , ofNullable() 

 

 of() λ©”μ†Œλ“œ : null이 μ•„λ‹Œ λͺ…μ‹œλœ 값을 κ°€μ§€λŠ” Optional 객체λ₯Ό λ°˜ν™˜ν•©λ‹ˆλ‹€.

      of() λ©”μ†Œλ“œλ₯Ό 톡해 μƒμ„±λœ Optional 객체에 null이 μ €μž₯되면 NullPointerException μ˜ˆμ™Έκ°€ λ°œμƒ

// Optional의 valueλŠ” μ ˆλŒ€ null이 μ•„λ‹ˆλ‹€.
Optional<String> optional = Optional.of("MyName");

 

 ofNullable() λ©”μ†Œλ“œ : μ°Έμ‘° λ³€μˆ˜μ˜ 값이 λ§Œμ— ν•˜λ‚˜ null이 될 κ°€λŠ₯성이 μžˆμ„ λ•Œ μ‚¬μš©

     λͺ…μ‹œλœ 값이 null이 μ•„λ‹ˆλ©΄ λͺ…μ‹œλœ 값을 κ°€μ§€λŠ” Optional 객체λ₯Ό λ°˜ν™˜

     λͺ…μ‹œλœ 값이 null이면 λΉ„μ–΄μžˆλŠ” Optional 객체λ₯Ό λ°˜ν™˜ν•©λ‹ˆλ‹€.

// Optional μ•ˆμ—λŠ” 값이 μžˆμ„ μˆ˜λ„ 있고 빈 객체일 μˆ˜λ„ μžˆλ‹€.
Optional<String> optional = Optional.ofNullable(getString());

String result = optional.orElse("other"); // 값이 μ—†λ‹€λ©΄ "other" λ₯Ό 리턴

Optional 객체에 μ ‘κ·Ό

1. get() : Optional 객체에 μ €μž₯된 값에 μ ‘κ·Ό

     λ§Œμ•½ Optional 객체에 μ €μž₯된 값이 null이면, NoSuchElementException μ˜ˆμ™Έκ°€ λ°œμƒν•©λ‹ˆλ‹€.

 

λ”°λΌμ„œ get() λ©”μ†Œλ“œλ₯Ό ν˜ΈμΆœν•˜κΈ° 전에 isPresent() λ©”μ†Œλ“œλ₯Ό μ‚¬μš©ν•˜μ—¬ Optional 객체에 μ €μž₯된 값이 null인지 μ•„λ‹Œμ§€λ₯Ό λ¨Όμ € ν™•μΈν•œ ν›„ ν˜ΈμΆœν•˜λŠ” 것이 μ’‹μŠ΅λ‹ˆλ‹€.

Optional<String> opt = Optional.ofNullable("μžλ°” Optional 객체");

if(opt.isPresent()) {
    System.out.println(opt.get()); //μžλ°” Optional 객체
}

 

2. orElse(), orElseGet(), orElseThrow() : null λŒ€μ‹ μ— λŒ€μ²΄ν•  값을 μ§€μ •

 

 orElse() μ €μž₯된 값이 μ‘΄μž¬ν•˜λ©΄ κ·Έ 값을 λ°˜ν™˜ν•˜κ³ , 값이 μ‘΄μž¬ν•˜μ§€ μ•ŠμœΌλ©΄ 인수둜 μ „λ‹¬λœ 값을 λ°˜ν™˜

 orElseGet()  μ €μž₯된 값이 μ‘΄μž¬ν•˜λ©΄ κ·Έ 값을 λ°˜ν™˜ν•˜κ³ , 값이 μ‘΄μž¬ν•˜μ§€ μ•ŠμœΌλ©΄ 인수둜 μ „λ‹¬λœ λžŒλ‹€ ν‘œν˜„μ‹μ˜ 결과값을 λ°˜ν™˜

orElseThrow()  μ €μž₯된 값이 μ‘΄μž¬ν•˜λ©΄ κ·Έ 값을 λ°˜ν™˜ν•˜κ³ , 값이 μ‘΄μž¬ν•˜μ§€ μ•ŠμœΌλ©΄ 인수둜 μ „λ‹¬λœ μ˜ˆμ™Έλ₯Ό λ°œμƒμ‹œν‚΄.

Optional<String> opt = Optional.empty(); // Optionalλ₯Ό null둜 μ΄ˆκΈ°ν™”ν•¨.

System.out.println(opt.orElse("빈 Optional 객체")); //빈 Optional 객체
System.out.println(opt.orElseGet(String::new));

Optional μ‚¬μš©ν•˜κΈ°

λ¨Όμ € μžλ°” 8 μ΄μ „μ—λŠ” λ‹€μŒκ³Ό 같이 null μ²΄ν¬κ°€ ν•„μš”ν–ˆμŠ΅λ‹ˆλ‹€.

// μžλ°” 8 이전
List<String> list = getList();
List<String> listOpt = list != null ? list : new ArrayList<>();

 

Optional<T> κ³Ό Lambda λ₯Ό μ΄μš©ν•˜λ©΄ μ’€ 더 κ°„λ‹¨ν•˜κ²Œ ν‘œν˜„ν•  수 μžˆμŠ΅λ‹ˆλ‹€.

List<String> listOpt = Optional.ofNullable(getList()).orElseGet(() -> new ArrayList<>());

 

null μ²΄ν¬λ‘œ 인해  μ§€μ €λΆ„ν•΄μ§„ μ½”λ“œμž…λ‹ˆλ‹€.

User user = getUser();
if (user != null) {
  Address address = user.getAddress();
  if (address != null) {
    String street = address.getStreet();
    if (street != null) {
      return street;
    }
  }
}
return "μ£Όμ†Œ μ—†μŒ";

 

map λ©”μ†Œλ“œ

 κ°’이 null  μ•„λ‹Œ 경우 : mapper λ₯Ό μ΄μš©ν•΄ κ³„μ‚°ν•œ 값을 μ €μž₯ν•˜λŠ” Optional 객체λ₯Ό λ¦¬ν„΄ν•©λ‹ˆλ‹€.

 κ°’이 null 인 경우  : 빈 Optional 객체λ₯Ό λ¦¬ν„΄ν•©λ‹ˆλ‹€.

public<U> Optional<U> map(Function<? super T, ? extends U> mapper)
public<U> Optional<U> flatMap(Function<? super T, Optional<U>> mapper)

 

map λ©”μ†Œλ“œλ₯Ό μ΄μš©ν•΄μ„œ κ°„λ‹¨ν•˜κ²Œ ν‘œν˜„ν•΄λ³΄κ² μŠ΅λ‹ˆλ‹€.

Optional<User> user = Optional.ofNullable(getUser());
Optional<Address> address = user.map(User::getAddress);
Optional<String> street = address.map(Address::getStreet);
String result = street.orElse("μ£Όμ†Œ μ—†μŒ");

// λ‹€μŒκ³Ό 같이 μΆ•μ•½ν•΄μ„œ μ“Έ 수 μžˆλ‹€.
user.map(User::getAddress)
    .map(Address::getStreet)
    .orElse("μ£Όμ†Œ μ—†μŒ");

 

+ Optional의 νŠΉμ„±μƒ 잘λͺ»μ‚¬μš©ν•˜λ©΄ μ‹œμŠ€ν…œ μ„±λŠ₯이 μ €ν•˜λ˜κΈ°λ„ ν•˜κΈ° λ•Œλ¬Έμ—  null이 λ°œμƒν•  κ°€λŠ₯성이 μ•„μ£Ό 높은 κ²½μš°μ— μ‚¬μš©ν•˜λŠ” 것이 μ’‹λ‹€κ³  ν•©λ‹ˆλ‹€. 

 

ν•™μŠ΅μ— 많이 도움이 된 λΈ”λ‘œκ·Έ 링크λ₯Ό  μ°Έμ‘°ν–ˆμŠ΅λ‹ˆλ‹€. πŸ™‚

 

참쑰 및 좜처

Optional 클래슀

Optionalμ΄λž€? Optional κ°œλ… 및 μ‚¬μš©λ²•

μ˜΅μ…”λ„ Optional