# Optional

# 1. Optional ์†Œ๊ฐœ

๋น„์–ด์žˆ์„ ์ˆ˜๋„ ์žˆ๊ณ , ์–ด๋– ํ•œ ๊ฐ’ ํ•˜๋‚˜๋งŒ ๋‹ด๊ณ  ์žˆ์„์ˆ˜๋„ ์žˆ๋Š” ์ธ์Šคํ„ด์Šค์˜ ํƒ€์ž…
Optional์ด ๊ฐ์ฒด๋ฅผ ๊ฐ์‹ธ๋Š” ๊ตฌ์กฐ

# 1-1. ๋“ฑ์žฅ๋ฐฐ๊ฒฝ : ์ฐธ์กฐํ˜• ๋ฉค๋ฒ„๋ณ€์ˆ˜ ์™€ NPE

1๏ธโƒฃ null ๊ด€๋ จ ๋ฌธ์ œ๋ฅผ ํ•ด๊ฒฐํ•˜๊ธฐ ์œ„ํ•ด

  1. ๋Ÿฐํƒ€์ž„์— NPE(NullPointerException)๋ผ๋Š” ์˜ˆ์™ธ๋ฅผ ๋ฐœ์ƒ์‹œํ‚ฌ ์ˆ˜ ์žˆ๋‹ค.
  2. NPE ๋ฐฉ์–ด๋ฅผ ์œ„ํ•ด์„œ ๋“ค์–ด๊ฐ„ null ์ฒดํฌ ๋กœ์ง ๋•Œ๋ฌธ์— ์ฝ”๋“œ ๊ฐ€๋…์„ฑ๊ณผ ์œ ์ง€ ๋ณด์ˆ˜์„ฑ์ด ๋–จ์–ด์ง„๋‹ค.
/* OnlineClass.java */
...
  public Progress progress;

	public Progress getProgress() {
    return progress;
  }

	public void setProgress(Progress progress) {
  	this.progress = progress;
  }
...

/* OptionalTestApp.java */
// ์ด์Šˆ์ƒํ™ฉ โ†’ ์ฐธ์กฐํ˜• ๋ฉค๋ฒ„ ๋ณ€์ˆ˜ ์‚ฌ์šฉ ์‹œ ์ดˆ๊ธฐํ™” ๋˜์ง€ ์•Š์•„ null ๊ฐ’์„ ์ฐธ์กฐ ํ•  ์ˆ˜ ์žˆ๋‹ค.
OnlineClass spring_boot = new OnlineClass(1, "spring boot", true);
// NullPointExecption ๋ฐœ์ƒ
Duration studyDuration = spring_boot.getProgress().getStudyDuration(); 
System.out.println(studyDuration);

2๏ธโƒฃ ์ž๋ฐ”8 ์ด์ „ ํ•ด๊ฒฐ๋ฐฉ๋ฒ•

// ๋ฐฉ๋ฒ•1. ์‚ฌ์ „์— null์„ ์ฒดํฌ โ†’ ์—๋Ÿฌ์— ๋Œ€ํ•œ ์ŠคํƒํŠธ๋ ˆ์ด์Šค๋ฅผ ๋ฝ‘๋Š” ๊ฒƒ ๋˜ํ•œ ๋ฆฌ์†Œ์Šค ๋‚ญ๋น„
public Progress getProgress() {
    if (progress == null) {
				throw new IllegalStateException();
    }
  	return progress;
}

// ๋ฐฉ๋ฒ•2. ํด๋ผ์ด์–ธํŠธ ์ฝ”๋“œ์—์„œ null์„ ํ™•์ธ โ†’ ์ด๋Š” ํด๋ผ์ด์–ธํŠธ์—์„œ ๋†“์นœ๋‹ค๋ฉด ์—๋Ÿฌ๊ฐ€ ๋ฐœ์ƒํ•  ์ˆ˜ ์žˆ์Œ.
Progress progress = spring_boot.getProgress();
if (progress != null) {
	  System.out.println(progress.getStudyDuration());
}

์ด๋ ‡๊ฒŒ if๋ฌธ์œผ๋กœ null์„ ์ฒดํฌํ•˜๊ฒŒ ๋˜๋ฉด get method๊ฐ€ ์‚ฌ์šฉ๋˜๋Š” ๋งŒํผ null ์ฒดํฌ๋ฅผ ํ•ด์ค˜์•ผํ•˜๋Š” ๋ฌธ์ œ๊ฐ€ ์žˆ๋‹ค. ๋น„์ฆˆ๋‹ˆ์Šค ๋กœ์ง๋ณด๋‹ค null ์ฒดํฌ ์ฝ”๋“œ๊ฐ€ ๊ธธ์–ด์ง€๋Š” ๋งˆ๋ฒ•์ด ๋ฐœ์ƒํ•œ๋‹ค.

3๏ธโƒฃ ์ž๋ฐ”8 : ๊ณ ํ†ต์Šค๋Ÿฌ์šด null ์ฒ˜๋ฆฌ๋ฅผ Optional์— ์œ„์ž„

  1. ์Šค์นผ๋ผ๋‚˜ ํ•˜์Šค์ผˆ๊ณผ ๊ฐ™์€ ํ•จ์ˆ˜ํ˜• ์–ธ์–ด๋“ค์€ ์ „ํ˜€ ๋‹ค๋ฅธ ๋ฐฉ๋ฒ•์œผ๋กœ null ๋ฌธ์ œ์„ ํ•ด๊ฒฐ
  2. ์ž๋ฐ”๊ฐ€ ์กด์žฌํ•˜์ง€ ์•Š๋Š” ๊ฐ’์„ ํ‘œํ˜„ํ•˜๊ธฐ ์œ„ํ•ด์„œ null์„ ์‚ฌ์šฉํ–ˆ๋‹ค๋ฉด, ์ด ํ•จ์ˆ˜ํ˜• ์–ธ์–ด๋“ค์€ ์กด์žฌํ• ์ง€ ์•ˆ ํ• ์ง€ ๋ชจ๋ฅด๋Š” ๊ฐ’์„ ํ‘œํ˜„ํ•  ์ˆ˜ ์žˆ๋Š” ๋ณ„๊ฐœ์˜ ํƒ€์ž…์„ ๊ฐ€์ง€๊ณ  ์žˆ๋‹ค.
  3. ์ด ์ปจ์…‰์„ ๋ชจํ‹ฐ๋ธŒ๋กœ Optional ํด๋ž˜์Šค ๋„์ž…

4๏ธโƒฃ Optional ์žฅ์ 

  1. NPE๋ฅผ ์œ ๋ฐœํ•  ์ˆ˜ ์žˆ๋Š” null์„ ์ง์ ‘ ๋‹ค๋ฃจ์ง€ ์•Š์•„๋„ ๋œ๋‹ค.
  2. ์ˆ˜๊ณ ๋กญ๊ฒŒ null ์ฒดํฌ๋ฅผ ์ง์ ‘ ํ•˜์ง€ ์•Š์•„๋„ ๋œ๋‹ค.
  3. ๋ช…์‹œ์ ์œผ๋กœ ํ•ด๋‹น ๋ณ€์ˆ˜๊ฐ€ null์ผ ์ˆ˜๋„ ์žˆ๋‹ค๋Š” ๊ฐ€๋Šฅ์„ฑ์„ ํ‘œํ˜„ํ•  ์ˆ˜ ์žˆ๋‹ค. (๋”ฐ๋ผ์„œ ๋ถˆํ•„์š”ํ•œ ๋ฐฉ์–ด ๋กœ์ง์„ ์ค„์ผ ์ˆ˜ ์žˆ๋‹ค!)

# 1-2. Optional ์ฃผ์˜ ์‚ฌํ•ญ

1๏ธโƒฃ Optional์€ returnย type ์—๋งŒ ์‚ฌ์šฉํ•˜๋Š” ๊ฒƒ์ด ์ข‹๋‹ค.

/* OnlineClass.java */
...
  // getter ์˜ return tpye ์„ Optional๋กœ ๋ช…์‹œ
  public Optional<Progress> getProgress() {
  	return Optional.ofNullable(progress);
	}
...
  1. ๋ฉ”์†Œ๋“œ Parameter๋กœ Optional์„ ์ •์˜ํ•ด๋‘๋ฉด NPE ๋ฐœ์ƒ ๊ฐ€๋Šฅ์„ฑ ์žˆ์Œ.

    // Parameter์— Optional ์ •์˜
    public void setProgress(Optional<Progress> progress) {
      	progress.ifPresent(p -> this.progress = p);
    }
    
    // ํ˜ธ์ถœ ์‹œ null.ifPresent(...) โ†’ NPE ๋ฐœ์ƒ
    {๊ฐ์ฒด}.setProgress(null);
    

    null ์ฒดํฌ๋ฅผ ํ•ด์ฃผ๋ฉด NPE ๋ฐœ์ƒ์„ ๋ง‰์„ ์ˆ˜ ์žˆ์ง€๋งŒ, Optional์„ ์‚ฌ์šฉํ•˜๋Š” ์˜๋ฏธ๊ฐ€ ์—†์–ด์ง„๋‹ค.

  2. Map์˜ Key์— Optional์„ ์‚ฌ์šฉํ•˜๋ฉด ์•ˆ๋œ๋‹ค.

    • Map ์ธํ„ฐํŽ˜์ด์Šค๋Š” Key๊ฐ€ Null์ผ ์ˆ˜ ์—†๋‹ค.
  3. ์ธ์Šคํ„ด์Šค ํ•„๋“œ์— Optional์€ ์ง€์–‘ํ•˜์ž.

    • ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ์ง€๋งŒ, ๋„๋ฉ”์ธ ํด๋ž˜์Šค ์„ค๊ณ„ ๋ฌธ์ œ์ด๋‹ค.
    • ํ•„๋“œ๊ฐ€ ์žˆ์„ ์ˆ˜ ๋„, ์—†์„ ์ˆ˜ ๋„ ์žˆ๋‹ค๋Š” ์˜๋ฏธ
    • ํ•ด๊ฒฐ ๋ฐฉ์•ˆ : ์ƒ์œ„/ํ•˜์œ„ ํด๋ž˜์Šค๋กœ ๋ถ„๋ฆฌ or Delegation ์‚ฌ์šฉ ๊ถŒ์žฅ

2๏ธโƒฃ Null ํ—ˆ์šฉ ์—ฌ๋ถ€์— ๋”ฐ๋ผ ofNuallable์„ ๊ณ ๋ คํ•ด๋ณด์ž.

  1. ofNullable : null์„ ๋ฐ›๋Š” ๊ฒƒ์„ ํ—ˆ์šฉํ•œ๋‹ค.
  2. of : null์„ ๋ฐ›์œผ๋ฉด NPE ๋ฐœ์ƒ

NPE๋ฅผ ๋ฐœ์ƒ์‹œํ‚ค์ง€ ์•Š์œผ๋ฉด์„œ null์„ ๋ฐ›์„ ์ˆ˜ ์žˆ๋Š” ๊ฒฝ์šฐ์— ์‚ฌ์šฉํ•˜์ž.

3๏ธโƒฃ primitiveType์˜ Optional์„ ์ ์ ˆํžˆ ์‚ฌ์šฉ

Optional.of(10); // ๋‚ด๋ถ€์—์„œ boxing, unBoxing์ด ์ด๋ฃจ์–ด์ง„๋‹ค. โ†’ ์„ฑ๋Šฅ ์ €ํ•˜

OptionalInt.of(10); // ๊ฐ primitive Type์— ๋งž๋Š” ํด๋ž˜์Šค๋ฅผ ์ œ๊ณต

4๏ธโƒฃ Optional return ๋ฉ”์†Œ๋“œ์—์„œ null์„ return ํ•˜์ง€ ๋ง์ž

// ์ง€ํ–ฅํ•ด์•ผํ•  ์ฝ”๋“œ โ†’ NPE ๋ฐœ์ƒ ๊ฐ€๋Šฅ
public Optional<Progress> getProgress() {
  	return null;
}

// ์ข‹์€ ์ฝ”๋“œ
public Optional<Progress> getProgress() {
  	return Optional.empty();
}

5๏ธโƒฃ Collection, Map, Stream Array, Optional ์€ Optional๋กœ ๊ฐ์‹ธ์ง€ ๋ง ๊ฒƒ

  • ์ปจํ…Œ์ด๋„ˆ ์„ฑ๊ฒฉ์˜ ์ธ์Šคํ„ด์Šค๋“ค์€ ์ด๋ฏธ ๋น„์–ด์žˆ๋‹ค๋Š” ๊ฒƒ์„ ํ‘œํ˜„ํ•  ์ˆ˜ ์žˆ๋‹ค.
  • ๊ทธ๋Ÿฌ๋ฏ€๋กœ Optional๋กœ ๊ฐ์‹ธ๋ฉด ๋‘ ๋ฒˆ ๊ฐ์‹ธ๊ฒŒ ๋จ. โ†’ ์˜๋ฏธ๊ฐ€ ์—†๋‹ค!

# 2. Optional API

# 2-1. Optional ๋งŒ๋“ค๊ธฐ

1๏ธโƒฃ ์„ ์–ธํ•˜๊ธฐ

์ œ๋„ค๋ฆญ์„ ์ œ๊ณตํ•˜๊ธฐ ๋•Œ๋ฌธ์—, ๋ณ€์ˆ˜๋ฅผ ์„ ์–ธํ•  ๋•Œ ๋ช…๊ธฐํ•œ ํƒ€์ž… ํŒŒ๋ผ๋ฏธํ„ฐ์— ๋”ฐ๋ผ์„œ ๊ฐ์Œ€ ์ˆ˜ ์žˆ๋Š” ๊ฐ์ฒด์˜ ํƒ€์ž…์ด ๊ฒฐ์ •๋œ๋‹ค.

Optional<Order> maybeOrder; // Order ํƒ€์ž…์˜ ๊ฐ์ฒด๋ฅผ ๊ฐ์Œ€ ์ˆ˜ ์žˆ๋Š” Optional ํƒ€์ž…์˜ ๋ณ€์ˆ˜
Optional<Member> optMember; // Member ํƒ€์ž…์˜ ๊ฐ์ฒด๋ฅผ ๊ฐ์Œ€ ์ˆ˜ ์žˆ๋Š” Optional ํƒ€์ž…์˜ ๋ณ€์ˆ˜
Optional<Address> address; // Address ํƒ€์ž…์˜ ๊ฐ์ฒด๋ฅผ ๊ฐ์Œ€ ์ˆ˜ ์žˆ๋Š” Optional ํƒ€์ž…์˜ ๋ณ€์ˆ˜

๋ณ€์ˆ˜๋ช…์€ ๊ทธ๋ƒฅ ํด๋ž˜์Šค ์ด๋ฆ„์„ ์‚ฌ์šฉํ•˜๊ธฐ๋„ ํ•˜์ง€๋งŒ maybe๋‚˜ opt์™€ ๊ฐ™์€ ์ ‘๋‘์–ด๋ฅผ ๋ถ™์—ฌ์„œ Optional ํƒ€์ž…์˜ ๋ณ€์ˆ˜๋ผ๋Š” ๊ฒƒ์„ ์ข€ ๋” ๋ช…ํ™•ํžˆ ๋‚˜ํƒ€๋‚ด๊ธฐ๋„ ํ•œ๋‹ค.

2๏ธโƒฃ ๊ฐ์ฒด ์ƒ์„ฑํ•˜๊ธฐ

  1. Optional.empty()

    • null์„ ๋‹ด๊ณ  ์žˆ๋Š”, ํ•œ ๋งˆ๋””๋กœ ๋น„์–ด์žˆ๋Š” Optional ๊ฐ์ฒด๋ฅผ ์–ป์–ด์˜จ๋‹ค.

    • ์ด ๋น„์–ด์žˆ๋Š” ๊ฐ์ฒด๋Š” Optional ๋‚ด๋ถ€์ ์œผ๋กœ ๋ฏธ๋ฆฌ ์ƒ์„ฑํ•ด๋†“์€ ์‹ฑ๊ธ€ํ„ด ์ธ์Šคํ„ด์Šค์ด๋‹ค.

      Optional<Member> maybeMember = Optional.empty();
      
  2. Optional.of()

    • null์ด ์•„๋‹Œ ๊ฐ์ฒด๋ฅผ ๋‹ด๊ณ  ์žˆ๋Š” Optional ๊ฐ์ฒด๋ฅผ ์ƒ์„ฑ

    • null์ด ๋„˜์–ด์˜ฌ ๊ฒฝ์šฐ, NPE๋ฅผ ๋˜์ง€๊ธฐ ๋•Œ๋ฌธ์—ย ์ฃผ์˜ํ•ด์„œ ์‚ฌ์šฉํ•˜์ž!

      Optional<Member> maybeMember = Optional.of(aMember);
      
  3. Optional.ofNullable()

    • null์ธ์ง€ ์•„๋‹Œ์ง€ ํ™•์‹ ํ•  ์ˆ˜ ์—†๋Š” ๊ฐ์ฒด๋ฅผ ๋‹ด๊ณ  ์žˆ๋Š” Optional ๊ฐ์ฒด๋ฅผ ์ƒ์„ฑ
    • Optional.empty()์™€ย Optional.ofNullable(value)๋ฅผ ํ•ฉ์ณ๋†“์€ ๋ฉ”์†Œ๋“œ๋กœ ์ดํ•ดํ•˜๋ฉด ํŽธํ•˜๋‹ค.
    • null์ด ๋„˜์–ด์˜ฌ ๊ฒฝ์šฐ, NPE๋ฅผ ๋˜์ง€์ง€ ์•Š๊ณ ย Optional.empty()์™€ ๋™์ผํ•˜๊ฒŒ ๋น„์–ด ์žˆ๋Š” Optional ๊ฐ์ฒด๋ฅผ ์–ป์–ด์˜จ๋‹ค.
    • ํ•ด๋‹น ๊ฐ์ฒด๊ฐ€ null์ธ์ง€ ์•„๋‹Œ์ง€ ์ž์‹ ์ด ์—†๋Š” ์ƒํ™ฉ์—์„œ๋Š” ์ด ๋ฉ”์†Œ๋“œ๋ฅผ ์‚ฌ์šฉํ•˜์ž.
    Optional<Member> maybeMember = Optional.ofNullable(aMember);
    Optional<Member> maybeNotMember = Optional.ofNullable(null);
    

# 2-2. Optional ๊ฐ’ ์—ฌ๋ถ€ ํ™•์ธ

  1. isPresent()
  2. isEmpty() Java11๋ถ€ํ„ฐ ์ œ๊ณต

# 2-3. Optional ๊ฐ’ ๊ฐ€์ ธ์˜ค๊ธฐ

์•„๋ž˜ ๋ฉ”์†Œ๋“œ๋“ค์€ ๋ชจ๋‘ Optional์ด ๋‹ด๊ณ  ์žˆ๋Š” ๊ฐ์ฒด๊ฐ€ ์กด์žฌํ•  ๊ฒฝ์šฐ ๋™์ผํ•˜๊ฒŒ ํ•ด๋‹น ๊ฐ’์„ ๋ฐ˜ํ™˜ ํ•˜์ง€๋งŒ, Optional์ด ๋น„์–ด์žˆ๋Š” ๊ฒฝ์šฐ(null์„ ๋‹ด๊ณ  ์žˆ๋Š” ๊ฒฝ์šฐ), ๋‹ค๋ฅด๊ฒŒ ์ž‘๋™

  1. get()

    • null์ผ ๊ฒฝ์šฐ NoSuchElementException ๋ฐœ์ƒ
    • ๊ฐ€๊ธ‰์  ์‚ฌ์šฉ์„ ํ•˜์ง€ ์•Š๋Š” ๊ฒƒ์„ ๊ถŒ์žฅ.
  2. orElse(T other)

    • null์ผ ๊ฒฝ์šฐ ๋„˜์–ด์˜จ ์ธ์ž(T) ๋ฅผ ๋ฐ˜ํ™˜
    • T๋Š” ์ธ์Šคํ„ด์Šค ํƒ€์ž…
  3. orElseGet(Supplier<? extends X>)

    • null์ผ ๊ฒฝ์šฐ ๋„˜์–ด์˜จ ํ•จ์ˆ˜ํ˜• ์ธ์ž๋ฅผ ํ†ตํ•ด ์ƒ์„ฑ๋œ ๊ฐ์ฒด๋ฅผ ๋ฐ˜ํ™˜
    • orElse(T other)์˜ ๊ฒŒ์œผ๋ฅธ ๋ฒ„์ „
    • ๋น„์–ด์žˆ๋Š” ๊ฒฝ์šฐ์—๋งŒ ํ•จ์ˆ˜๊ฐ€ ํ˜ธ์ถœ๋˜๊ธฐ ๋•Œ๋ฌธ์—ย orElse(T other)ย ๋Œ€๋น„ ์„ฑ๋Šฅ์ƒ ์ด์ ์„ ๊ธฐ๋Œ€ํ•  ์ˆ˜ ์žˆ์Œ.
  4. orElseThrow(Supplier<? extends X> exceptionSupplier)

    • null์ผ ๊ฒฝ์šฐ ๋„˜์–ด์˜จ ํ•จ์ˆ˜ํ˜• ์ธ์ž๋ฅผ ํ†ตํ•ด ์ƒ์„ฑ๋œ ์˜ˆ์™ธ๋ฅผ ๋˜์ง„๋‹ค.
    • default : NoSuchElementException
  5. ifPresent(Consumer)

    • ๊ฐ’์ด ์žˆ๋Š” ๊ฒฝ์šฐ ๊ฐ’์„ ๊ฐ€์ง€๊ณ  Consumer ํ•จ์ˆ˜ ๋™์ž‘
    // 1. get()
    OnlineClass onlineClass = optional.get(); // NoSuchElementException ๋ฐœ์ƒ
    
    // 2. isPresent() + get() = ๋จผ์ € ํ™•์ธํ›„ ๊บผ๋‚ธ๋‹ค  ๋ฒˆ๊ฑฐ๋กญ๋‹ค
    if (optional.isPresent()) {
    	OnlineClass onlineClass = optional.get();
    	System.out.println(onlineClass.getTitle());
    }
    
    // 3. ifPresent(Consumer) = ๊ฐ’์ด ์žˆ๋Š” ๊ฒฝ์šฐ๋งŒ ํ•จ์ˆ˜๊ฐ€ ๋™์ž‘ํ•œ๋‹ค!
    optional.ifPresent(oc -> System.out.println(oc.getTitle()));
    

# 2-4. Optional ํ•„ํ„ฐ/๋ณ€ํ™˜

  1. Optional map(Function)
  2. Optional filter(Predicate)
  3. Optional flatMap(Function) : Optional ์•ˆ์˜ ์ธ์Šคํ„ด์Šค๊ฐ€ Optional์ธ ๊ฒฝ์šฐ ์‚ฌ์šฉ

1๏ธโƒฃ map์„ ํ™œ์šฉํ•ด๋ณด์ž.

์ฃผ๋ฌธ์„ ํ•œ ํšŒ์›์ด ์‚ด๊ณ  ์žˆ๋Š” ๋„์‹œ๋ฅผ ๋ฐ˜ํ™˜ํ•˜๋Š” ๋ฉ”์†Œ๋“œ๋‹ค. (๊ธฐ๋ณธ๊ฐ’์€ Seoul ์ด๋‹ค.)

// AS-WAS
public String getCityOfMemberFromOrder(Order order) {
	if (order == null) {
		return "Seoul";
	}
	Member member = order.getMember();
	if (member == null) {
		return "Seoul";
	}
	Address address = member.getAddress();
	if (address == null) {
		return "Seoul";
	}
	String city = address.getCity();
	if (city == null) {
		return "Seoul";
	}
	return city;
}

์‚ฌ๋ฐฉ์—์„œ return ํ•ด์ค˜์•ผ ํ•˜์—ฌ ๊ฐ€๋…์„ฑ์ด ๋–จ์–ด์ง€๊ณ , ์œ ์ง€๋ณด์ˆ˜๊ฐ€ ์ข‹์ง€ ์•Š์€ ์ฝ”๋“œ๊ฐ€ ์žˆ๋‹ค.

// TO-BE
public String getCityOfMemberFromOrder(Order order) {
	return Optional.ofNullable(order)
			.map(Order::getMember)
			.map(Member::getAddress)
			.map(Address::getCity)
			.orElse("Seoul");
}

์ „ํ†ต์ ์ธ NPE ๋ฐฉ์–ด ํŒจํ„ด์— ๋น„ํ•ด ํ›จ์”ฌ ๊ฐ„๊ฒฐํ•˜๊ณ  ๋ช…ํ™•ํ•ด์ง„๋‹ค!

์šฐ์„  ๊ธฐ์กด์— ์กด์žฌํ•˜๋˜ ์กฐ๊ฑด๋ฌธ๋“ค์ด ๋ชจ๋‘ ์‚ฌ๋ผ์ง€๊ณ  Optional์˜ ์ˆ˜๋ คํ•œ(fluent) API์— ์˜ํ•ด์„œ ๋‹จ์ˆœํ•œ ๋ฉ”์†Œ๋“œ ์ฒด์ด๋‹์œผ๋กœ ๋ชจ๋‘ ๋Œ€์ฒด๋œ๋‹ค.

2๏ธโƒฃ map : ๋ฉ”์†Œ๋“œ ์ฒด์ด๋‹ ์„ค๋ช…

  1. ofNullable()ย ์ •์  ํŒฉํ† ๋ฆฌ ๋ฉ”์†Œ๋“œ๋ฅผ ํ˜ธ์ถœํ•˜์—ฌ Order ๊ฐ์ฒด๋ฅผ Optional๋กœ ๊ฐ์‹ผ๋‹ค.
    • ํ˜น์‹œ Order ๊ฐ์ฒด๊ฐ€ null์ธ ๊ฒฝ์šฐ๋ฅผ ๋Œ€๋น„ํ•˜์—ฌย of()ย ๋Œ€์‹ ์—ย ofNullable()์„ ์‚ฌ์šฉํ•˜๋Š” ๊ฒƒ.
  2. 3๋ฒˆ์˜ย map()ย ๋ฉ”์†Œ๋“œ์˜ ์—ฐ์‡„ ํ˜ธ์ถœ์„ ํ†ตํ•ด์„œ Optional ๊ฐ์ฒด๋ฅผ 3๋ฒˆ ๋ณ€ํ™˜ํ•œ๋‹ค.
    • ๋งค ๋ฒˆ ๋‹ค๋ฅธ ๋ฉ”์†Œ๋“œ ๋ ˆํผ๋Ÿฐ์Šค๋ฅผ ์ธ์ž๋กœ ๋„˜๊ฒจ์„œ Optional์— ๋‹ด๊ธด ๊ฐ์ฒด์˜ ํƒ€์ž…์„ ๋ฐ”๊ฟ”์ค€๋‹ค.
    • Optional<Order>ย ->ย Optional<Member>ย ->ย Optional<Address>ย ->ย Optional<String>
  3. ๋งˆ๋ฌด๋ฆฌ ์ž‘์—…์œผ๋กœย orElse()ย ๋ฉ”์†Œ๋“œ๋ฅผ ํ˜ธ์ถœํ•˜์—ฌ ์ด ์ „ ๊ณผ์ •์„ ํ†ตํ•ด ์–ป์€ Optional์ด ๋น„์–ด์žˆ์„ ๊ฒฝ์šฐ, ๋””ํดํŠธ๋กœ ์‚ฌ์šฉํ•  ๋„์‹œ ์ด๋ฆ„์„ ์„ธํŒ…ํ•ด์ฃผ๋ฉด ๋œ๋‹ค.

3๏ธโƒฃ fileter๋ฅผ ์‚ฌ์šฉํ•ด๋ณด์ž.

Java8 ์ด ์ „์— NPE ๋ฐฉ์ง€๋ฅผ ์œ„ํ•ด์„œ ๋‹ค์Œ๊ณผ ๊ฐ™์ด null ์ฒดํฌ๋กœ ์‹œ์ž‘ํ•˜๋Š” if ์กฐ๊ฑด๋ฌธ ํŒจํ„ด์„ ๋งŽ์ด ์‚ฌ์šฉํ•ด์™”๋‹ค.

if (obj != null && obj.do() ...)

์˜ˆ๋ฅผ ๋“ค์–ด, ์ฃผ์–ด์ง„ ์‹œ๊ฐ„(๋ถ„) ๋‚ด์— ์ƒ์„ฑ๋œ ์ฃผ๋ฌธ์„ ํ•œ ๊ฒฝ์šฐ์—๋งŒ ํ•ด๋‹น ํšŒ์› ์ •๋ณด๋ฅผ ๊ตฌํ•˜๋Š” ๋ฉ”์†Œ๋“œ๋ฅผ ์œ„ ํŒจํ„ด์œผ๋กœ ์ž‘์„ฑํ•ด๋ณด๋ฉด ๋‹ค์Œ๊ณผ ๊ฐ™๋‹ค.

public Member getMemberIfOrderWithin(Order order, int min) {
	if (order != null && order.getDate().getTime() > System.currentTimeMillis() - min * 1000) {
		return order.getMember();
	}
}
  1. if ์กฐ๊ฑด๋ฌธ ๋‚ด์— null ์ฒดํฌ์™€ ๋น„์ง€๋‹ˆ์Šค ๋กœ์ง์ด ํ˜ผ์žฌ๋˜์–ด ์žˆ์–ด์„œ ๊ฐ€๋…์„ฑ์ด ๋–จ์–ด์ง„๋‹ค.
  2. ๊ฒŒ๋‹ค๊ฐ€ null์„ ๋ฆฌํ„ดํ•  ์ˆ˜ ์žˆ๊ธฐ ๋•Œ๋ฌธ์— ๋ฉ”์†Œ๋“œ ํ˜ธ์ถœ๋ถ€์— NPE ์œ„ํ—˜์„ ์ „ํŒŒํ•˜๊ณ  ์žˆ๋‹ค.

filter๋ฅผ ์ ์šฉํ•ด๋ณด์ž.

public Optional<Member> getMemberIfOrderWithin(Order order, int min) {
	return Optional.ofNullable(order)
			.filter(o -> o.getDate().getTime() > System.currentTimeMillis() - min * 1000)
			.map(Order::getMember);
}
  1. if ์กฐ๊ฑด๋ฌธ ์—†์ด ๋ฉ”์†Œ๋“œ ์—ฐ์‡„ ํ˜ธ์ถœ๋งŒ์œผ๋กœ๋„ ์ข€ ๋” ์ฝ๊ธฐ ํŽธํ•œ ์ฝ”๋“œ๋ฅผ ์ž‘์„ฑํ•  ์ˆ˜ ์žˆ๋‹ค.
  2. ๋ฟ๋งŒ ์•„๋‹ˆ๋ผ, ๋ฉ”์†Œ๋“œ์˜ ๋ฆฌํ„ด ํƒ€์ž…์„ Optional๋กœ ์‚ฌ์šฉํ•จ์œผ๋กœ์จ ํ˜ธ์ถœ์ž์—๊ฒŒ ํ•ด๋‹น ๋ฉ”์†Œ๋“œ๊ฐ€ null์„ ๋‹ด๊ณ  ์žˆ๋Š” Optional์„ ๋ฐ˜ํ™˜ํ•  ์ˆ˜๋„ ์žˆ๋‹ค๋Š” ๊ฒƒ์„ ๋ช…์‹œ์ ์œผ๋กœ ์•Œ๋ ค์ค€๋‹ค.

# Reference

Last Updated: 6/18/2023, 2:13:15 PM