item 55 SeungminLee - JAVA-JIKIMI/EFFECTIVE-JAVA3 GitHub Wiki

item 55

์˜ต์…”๋„ ๋ฐ˜ํ™˜์€ ์‹ ์ค‘ํžˆ ํ•˜๋ผ

ํ•ต์‹ฌ์ •๋ฆฌ

๊ฐ’์„ ๋ฐ˜ํ™˜ํ•˜์ง€ ๋ชปํ•  ๊ฐ€๋Šฅ์„ฑ์ด ์žˆ๊ณ , ํ˜ธ์ถœํ•  ๋•Œ๋งˆ๋‹ค ๋ฐ˜ํ™˜๊ฐ’์ด ์—†์„ ๊ฐ€๋Šฅ์„ฑ์„ ์—ผ๋‘์— ๋‘ฌ์•ผ ํ•˜๋Š” ๋ฉ”์„œ๋“œ๋ผ๋ฉด ์˜ต์…”๋„์„ ๋ฐ˜ํ™˜ํ•ด์•ผ ํ•  ์ƒํ™ฉ์ผ ์ˆ˜ ์žˆ๋‹ค. ํ•˜์ง€๋งŒ ์˜ต์…”๋„ ๋ฐ˜ํ™˜์—๋Š” ์„ฑ๋Šฅ ์ €ํ•˜๊ฐ€ ๋’ค๋”ฐ๋ฅด๋‹ˆ, ์„ฑ๋Šฅ์— ๋ฏผ๊ฐํ•œ ๋ฉ”์„œ๋“œ๋ผ๋ฉด null์„ ๋ฐ˜ํ™˜ํ•˜๊ฑฐ๋‚˜ ์˜ˆ์™ธ๋ฅผ ๋˜์ง€๋Š” ํŽธ์ด ๋‚˜์„ ์ˆ˜ ์žˆ๋‹ค. ๋˜ํ•œ ์˜ต์…”๋„์„ ๋ฐ˜ํ™˜๊ฐ’ ์ด์™ธ์˜ ์šฉ๋„๋กœ ์“ฐ๋Š” ๊ฒฝ์šฐ๋Š” ๋งค์šฐ ๋“œ๋ฌผ๋‹ค.


์ž๋ฐ” 8 ์ด์ „์— ํŠน์ •ํ•œ ์กฐ๊ฑด์—์„œ ๊ฐ’์„ ๋ฐ˜ํ™˜ํ•  ์ˆ˜ ์—†์„ ๋•Œ

  1. ์˜ˆ์™ธ๋ฅผ ๋˜์ง„๋‹ค
    • ์˜ˆ์™ธ๋Š” ์ง„์งœ ์˜ˆ์™ธ์ ์ธ ์ƒํ™ฉ์—์„œ๋งŒ ์‚ฌ์šฉํ•ด์•ผ ํ•œ๋‹ค.
    • ์˜ˆ์™ธ๋ฅผ ์ƒ์„ฑํ•  ๋•Œ ์Šคํƒ ์ถ”์  ์ „์ฒด๋ฅผ ์บก์ณํ•˜๋ฏ€๋กœ ๋น„์šฉ๋„ ๋งŒ๋งŒ์น˜ ์•Š๋‹ค.
  2. null ์„ ๋ฐ˜ํ™˜ํ•œ๋‹ค
    • null์„ ๋ฐ˜ํ™˜ํ•  ์ˆ˜ ์žˆ๋Š” ๋ฉ”์„œ๋“œ๋ฅผ ํ˜ธ์ถœํ•  ๋•Œ๋Š” ๋ณ„๋„์˜ null ์ฒ˜๋ฆฌ ์ฝ”๋“œ๋ฅผ ์ถ”๊ฐ€ํ•ด๋Œœ ํ•œ๋‹ค.
    • null์ฒ˜๋ฆฌ๋ฅผ ๋ฌด์‹œํ•œ๋‹ค๋ฉด ์‹ค์ œ ์›์ธ๊ณผ๋Š” ์ „ํ˜€ ์ƒ๊ด€ ์—†๋Š” ์ฝ”๋“œ์—์„œ NullPointerException์ด ๋ฐœ์ƒํ•  ์ˆ˜ ์žˆ๋‹ค.

์ž๋ฐ” 8 ์ดํ›„์— ์ถ”๊ฐ€๋œ ๋˜ ํ•˜๋‚˜์˜ ์„ ํƒ์ง€ Optional

Optional๋Š” null์ด ์•„๋‹Œ Tํƒ€์ž… ์ฐธ์กฐ๋ฅผ ํ•˜๋‚˜ ๋‹ด๊ฑฐ๋‚˜ ํ˜น์€ ์•„๋ฌด๊ฒƒ๋„ ๋‹ด์ง€ ์•Š์„ ์ˆ˜ ์žˆ๋‹ค. ์•„๋ฌด๊ฒƒ๋„ ๋‹ด์ง€ ์•Š์€ ์˜ต์…”๋„์€ ๋น„์—ˆ๋‹ค๊ณ  ๋งํ•œ๋‹ค. ๋ฐ˜๋Œ€๋กœ ์–ด๋–ค ๊ฐ’์„ ๋‹ด์€ ์˜ต์…”๋„์€ ๋น„์–ด์žˆ์ง€ ์•Š๋‹ค๊ณ  ํ•œ๋‹ค. ์˜ต์…”๋„์€ ์›์†Œ๋ฅผ ์ตœ๋Œ€ 1๊ฐœ ๊ฐ€์งˆ ์ˆ˜ ์žˆ๋Š” ๋ถˆ๋ณ€ ์ปฌ๋ ‰์…˜์ด๋‹ค.

  • ๋ถˆ๋ณ€ ์ปฌ๋ ‰์…˜์ด๋ผ๊ณ  ํ•ด์„œ Optional๊ฐ€ Collection๋ฅผ ๊ตฌํ˜„ํ•œ ๊ฒƒ์€ ์•„๋‹ˆ๋‹ค. Optional๋Š” Object๋ฅผ ์ƒ์†๋ฐ›์•˜๋‹ค.
  • ๋ณดํ†ต์€ T๋ฅผ ๋ฐ˜ํ™˜ํ•ด์•ผ ํ•˜์ง€๋งŒ ํŠน์ • ์กฐ๊ฑด์—์„œ๋Š” ์•„๋ฌด๊ฒƒ๋„ ๋ฐ˜ํ™˜ํ•˜์ง€ ์•Š์•„์•ผ ํ•  ๋•Œ T ๋Œ€์‹  Optional๋ฅผ ๋ฐ˜ํ™˜ํ•˜๋ฉด ๋œ๋‹ค.
  • Optional์„ ๋ฐ˜ํ™˜ํ•˜๋Š” ๋ฉ”์„œ๋“œ๋Š” ์˜ˆ์™ธ๋ฅผ ๋˜์ง€๋Š” ๋ฉ”์„œ๋“œ๋ณด๋‹ค ์œ ์—ฐํ•˜๊ณ  ์‚ฌ์šฉํ•˜๊ธฐ ์‰ฌ์šฐ๋ฉฐ, null์„ ๋ฐ˜ํ˜ธ๋‚˜ํ•˜๋Š” ๋ฉ”์„œ๋“œ๋ณด๋‹ค ์˜ค๋ฅ˜ ๊ฐ€๋Šฅ์„ฑ์ด ์ ๋‹ค.

์ปฌ๋ ‰์…˜์—์„œ ์ตœ๋Œ€ ๊ฐ’์„ ๊ตฌํ•˜๋Š” ํ•จ์ˆ˜ max (์˜ˆ์™ธ/Optional ์‚ฌ์šฉ)

/*
    Optional ์„ ์‚ฌ์šฉํ•˜์ง€ ์•Š๊ณ  ์—์™ธ๋ฅผ ๋˜์ ธ์ค€๋‹ค
     */
    public static <E extends Comparable<E>> E max(Collection<E> c) {
        if (c.isEmpty())
            throw new IllegalArgumentException("๋นˆ ์ปฌ๋ ‰์…˜");

        E result = null;
        for (E e: c) {
            if(result == null || e.compareTo(result) > 0)
                result = Objects.requireNonNull(e);

        }
        return result;
    }

    /*
    Optional ์„ ์‚ฌ์šฉ
     */
    public static <E extends Comparable<E>> Optional<E> maxOptional(Collection<E> c) {
        if (c.isEmpty())
            return Optional.empty();

        E result = null;
        for (E e: c) {
            if(result == null || e.compareTo(result) > 0)
                result = Objects.requireNonNull(e);

        }
        return Optional.of(result);
    }

		/*
    Optional + stream ์‚ฌ์šฉ
		 * Stream์˜ ์ข…๋‹จ ์—ฐ์‚ฐ ์ค‘ ์ƒ๋‹น์ˆ˜๊ฐ€ Optional์„ ๋ฐ˜ํ™˜ํ•œ๋‹ค 
     */
    public static <E extends Comparable<E>> Optional<E> maxStream(Collection<E> c) {
        return c.stream().max(Comparator.naturalOrder());
    }
  • Optional์„ ์‚ฌ์šฉํ•  ๋•Œ๋Š” ์ ์ ˆํ•œ ์ •์  ์ฑ…ํ„ฐ๋ฆฌ๋ฅผ ์‚ฌ์šฉํ•ด ์˜ต์…”๋„์„ ์ƒ์„ฑํ•ด์ฃผ๋ฉด ๋œ๋‹ค.
  • Optional.empty() ๋Š” ๋นˆ ์˜ต์…”๋„์„ ๋ฐ˜ํ™˜ํ•œ๋‹ค.
  • Optional.of(value) ์— Null์„ ๋„ฃ์œผ๋ฉด NullPointerException ์ด ๋ฐœ์ƒํ•˜๋‹ˆ ์ฃผ์˜ํ•˜์ž
  • Optional.ofNullable(value)๋ฅผ ํ•˜๋ฉด Null์„ ๋ฐ˜ํ™˜ํ•  ์ˆ˜ ์žˆ๊ธฐ๋Š”ํ•˜์ง€๋งŒ ์˜ต์…”๋„์„ ๋„์ž…ํ•œ ์ทจ์ง€๋ฅผ ์™„์ „ํžˆ ๋ฌด์‹œํ•˜๊ธฐ ๋•Œ๋ฌธ์— ์˜ต์…”๋„์„ ๋ฐ˜ํ™˜ํ•˜๋Š” ๋ฉ”์†Œ๋“œ์—์„œ๋Š” ์ ˆ๋Œ€ Null์„ ๋ฐ˜ํ™˜ํ•˜์ง€ ๋ง์ž

Optional ๋ฐ˜ํ™˜์„ ์„ ํƒํ•ด์•ผ ํ•˜๋Š” ๊ธฐ์ค€์€?

Optional์€ ๊ฒ€์‚ฌ ์˜ˆ์™ธ์™€ ์ทจ์ง€๊ฐ€ ๋น„์Šทํ•˜๋‹ค. ์ฆ‰, ๋ฐ˜ํ™˜๊ฐ’์ด ์—†์„ ์ˆ˜๋„ ์žˆ์Œ์„ API ์‚ฌ์šฉ์ž์—๊ฒŒ ๋ช…ํ™•ํžˆ ์•Œ๋ ค์ค€๋‹ค. ๋น„๊ฒ€์‚ฌ ์˜ˆ์™ธ๋ฅผ ๋˜์ง€๊ฑฐ๋‚˜ null์„ ๋ฐ˜ํ™˜ํ•œ๋‹ค๋ฉด API ์‚ฌ์šฉ์ž๊ฐ€ ๊ทธ ์‚ฌ์‹ค์„ ์ธ์ง€ํ•˜์ง€ ๋ชปํ•œ๋‹ค. ํ•˜์ง€๋งŒ ๊ฒ€์‚ฌ ์˜ˆ์™ธ๋ฅผ ๋˜์ง€๋ฉด ํด๋ผ์ด์–ธํŠธ์—์„œ๋Š” ๋ฐ˜๋“œ์‹œ ์ด์— ๋Œ€์ฒ˜ํ•˜๋Š” ์ฝ”๋“œ๋ฅผ ์ž‘์„ฑํ•ด ๋„ฃ์–ด์•ผ ํ•œ๋‹ค. ๋น„์Šทํ•˜๊ฒŒ, ๋ฉ”์„œ๋“œ๊ฐ€ Optional์„ ๋ฐ˜ํ™˜ํ•œ๋‹ค๋ฉด ํด๋ผ์ด์–ธํŠธ๋Š” ๊ฐ’์„ ๋ฐ›์ง€ ๋ชปํ–ˆ์„ ๋•Œ ์ทจํ•  ํ–‰๋™์„ ์„ ํƒํ•ด์•ผ ํ•œ๋‹ค.

Optional๋กœ ๊ฐ’์„ ๋ฐ›์ง€ ๋ชป ํ–ˆ์„ ๋•Œ ์ทจํ•ด์•ผ ํ•˜๋Š” ํ–‰๋™

int result = maxOptional(empty).orElse(-1);

// Supplier ๊ณผ orElseGet ์‚ฌ์šฉ  
Supplier<Integer> defaultSupplier = () -> -1;
int unWrap = resultNumber1.orElseGet(defaultSupplier)

// ๊ฐ’์ด ์žˆ์„๊ฑฐ๋ผ ํ™•์‹ ํ•˜๊ณ  get 
int result4 = maxOptional(number1).get();

// orElseThrow
int result2 = maxOptional(number1).orElseThrow(IllegalArgumentException::new);
int result3 = maxOptional(empty).orElseThrow(NullPointerException::new);
  1. orElse() ๋กœ ๊ธฐ๋ณธ๊ฐ’ ์„ค์ •ํ•ด์ฃผ๊ธฐ
  2. orElseThrow ๋กœ ์›ํ•˜๋Š” ์˜ˆ์™ธ ๋˜์ง€๊ธฐ (maxOptional ์— ๊ฑธ์–ด๋‘” ์˜ˆ์™ธ๊ฐ€ ๋ฐœ์ƒํ•˜๋ฉด orElseThrow์— ์žˆ๋Š” ์˜ˆ์™ธ๋ฅผ ๋ฐœ์ƒ์‹œํ‚จ๋‹ค)
  3. ํ•ญ์ƒ ๊ฐ’์ด ์ฑ„์›Œ์ ธ ์žˆ๋‹ค๊ณ  ํ™•์‹ ํ•˜๊ณ  get ์‚ฌ์šฉ
  4. ๊ธฐ๋ณธ๊ฐ’ ์„ค์ •ํ•˜๋Š” ๋น„์šฉ์ด ๋ถ€๋‹ต์Šค๋Ÿฝ๋‹ค๋ฉด Supplier๋ฅผ ์ธ์ˆ˜๋กœ ๋ฐ›๋Š” orElseGet์„ ์‚ฌ์šฉํ•˜์ž. ๊ฐ’์ด ์ฒ˜์Œ์œผ๋กœ ํ•„์š”ํ•˜๊ฒŒ ๋ ๋•Œ Supplier๋กœ ์ƒ์„ฑํ•ด์„œ ์ดˆ๊ธฐ ์„ค์ • ๋น„์šฉ์„ ๋‚ฎ์ถœ ์ˆ˜ ์žˆ๋‹ค.
  5. ์œ„์— ์ œ๊ณต๋œ ๊ธฐ๋ณธ ๋ฉ”์„œ๋“œ ์™ธ์— filter, map, flatMap, ifPresent ๋ฅผ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋‹ค.
  6. ifPresent๋Š” ๋งŽ์€ ์ƒ๋‹น์ˆ˜ ์•„ํผ ์–ธ๊ธ‰ํ•œ ๋ฉ”์„œ๋“œ๋“ค๋กœ ๋Œ€์ฒดํ•  ์ˆ˜ ์žˆ๋‹ค. (์‚ฌ์šฉ ๋น„์ถ”)
//ifPresent ์˜ˆ์‹œ 
Optional<ProcessHandler> parentProcess = ph.parent();
System.out.println("PID:" + (parentProcess.isPresent() ? String.valueOf(parentProcess.get().pid()) : "N/A"));

//Optional map ์‚ฌ์šฉ 
System.out.println("PID:" + ph.parent().map(h->String.valueOf(h.pid())).orElse("N/A"));

// stream ์‚ฌ์šฉ 
// isPresent๊ฐ€ ์‚ฌ์‹ค์ผ ๊ฒฝ์šฐ ๊ฐ’์„ ๊บผ๋‚ด์„œ Optional::get์— ๋งตํ•‘
streamOfOptionals.filter(Optional::isPresent).map(Optional::get)

//optional stream ์‚ฌ์šฉ 
//optional์— ๊ฐ’์ด ์žˆ๊ฑฐ๋‚˜ ์—†๊ฑฐ๋‚˜ ๋‹ค stream์œผ๋กœ ๋ณ€ํ™˜์„ ํ•ด์คŒ
streamOfOptionals.flatMap(Optional::stream)

์ปฌ๋ ‰์…˜, ์ŠคํŠธ๋ฆผ, ๋ฐฐ์—ด, ์˜ต์…”๋„ ๊ฐ™์€ ์ปจํ…Œ์ด๋„ˆ ํƒ€์ž…์€ ์˜ต์…”๋„๋กœ ๊ฐ์‹ธ๋ฉด ์•ˆ๋œ๋‹ค. ๋นˆ Optional<List>๋ฅผ ๋ฐ˜ํ™˜ํ•˜๊ธฐ ๋ณด๋‹ค๋Š” ๋นˆ List๋ฅผ ๋ฐ˜ํ™˜ํ•˜๋Š”๊ฒŒ ์ข‹๋‹ค. ๋นˆ ์ปจํ…Œ์ด๋„ˆ๋ฅผ ๊ทธ๋Œ€๋กœ ๋ฐ˜ํ™˜ํ•˜๋ฉด ํด๋ผ์ด์–ธํŠธ์— ์˜ต์…”๋„ ์ฒ˜๋ฆฌ ์ฝ”๋“œ๋ฅผ ๋„ฃ์ง€ ์•Š์•„๋„ ๋œ๋‹ค.

์–ด๋–ค ๊ฒฝ์šฐ ๋ฉ”์„œ๋“œ ๋ฐ˜ํ™˜ ํƒ€์ž…์„ T๋Œ€์‹  Optional๋กœ ํ•ด์ค˜์•ผ ํ•˜๋‚˜?

๊ฒฐ๊ณผ๊ฐ€ ์—†์„ ์ˆ˜ ์žˆ์œผ๋ฉฐ, ํด๋ผ์ด์–ธํŠธ๊ฐ€ ์ด ์ƒํ™ฉ์„ ํŠน๋ณ„ํ•˜๊ฒŒ ์ฒ˜๋ฆฌํ•ด์•ผ ํ•œ๋‹ค๋ฉด Optional๋ฅผ ๋ฐ˜ํ™˜ํ•œ๋‹ค.

  • Optional๋„ ์—„์—ฐํ•˜๊ฒŒ ์ƒˆ๋กœ ํ• ๋‹นํ•˜๊ณ  ์ดˆ๊ธฐํ™”ํ•ด์•ผ ํ•˜๋Š” ๊ฐ์ฒด์ด๊ณ , ๊ทธ ์•ˆ์—์„œ ๊ฐ’์„ ๊บผ๋‚ด๋ ค๋ฉด ๋ฉ”์„œ๋“œ๋ฅผ ํ˜ธ์ถœํ•ด์•ผ ํ•˜๋‹ˆ ํ•œ ๋‹จ๊ณ„๋ฅผ ๋” ๊ฑฐ์นœ๋‹ค. ๊ทธ๋ž˜์„œ ์„ฑ๋Šฅ์ด ์ค‘์š”ํ•œ ์ƒํ™ฉ์—์„œ๋Š” ์˜ต์…”๋„์ด ๋งž์ง€ ์•Š์„ ์ˆ˜ ์žˆ๋‹ค.
  • ๋ฐ•์‹ฑ๋œ ๊ธฐ๋ณธํƒ€์ž…์„ ๋‹ด๋Š” ์˜ต์…”๋„์€ ๊ธฐ๋ณธ ํƒ€์ž… ์ž์ฒด๋ณด๋‹ค ๋ฌด๊ฒ๋‹ค. ๊ทธ๋ž˜์„œ OptionalInt, OptionalLong, OptionalDouble ์„ ์‚ฌ์šฉํ•œ๋‹ค. ๋ฐ•์‹ฑ๋œ ๊ธฐ๋ณธ ํƒ€์ž…์„ ๋‹ด์€ ์˜ต์…”๋„์„ ๋ฐ˜ํ™˜ํ•˜๋Š” ์ผ์€ ์—†๋„๋ก ํ•˜์ž.

์˜ต์…”๋„์„ ๋งต์˜ ๊ฐ’์œผ๋กœ ์‚ฌ์šฉํ•˜๋ฉด ์ ˆ๋Œ€ ์•ˆ๋œ๋‹ค.

๊ฐ’์œผ๋กœ ์‚ฌ์šฉํ•œ๋‹ค๋ฉด ๋งต ์•ˆ์— ํ‚ค๊ฐ€ ์—†๋‹ค๋Š” ์‚ฌ์‹ค์„ ๋‚˜ํƒ€๋‚ด๋Š” ๋ฐฉ๋ฒ•์ด ๋‘๊ฐ€์ง€๊ฐ€ ๋œ๋‹ค. ํ•˜๋‚˜๋Š” ํ‚ค ์ž์ฒด๊ฐ€ ์—†๋Š” ๊ฒฝ์šฐ๊ณ  ๋‹ค๋ฅธ ํ•˜๋‚˜๋Š” ํ‚ค๋Š” ์žˆ์ง€๋งŒ ๊ทธ ํ‚ค๊ฐ€ ์†์ด ๋นˆ ์˜ต์…”๋„์ผ ๊ฒฝ์šฐ๋‹ค. ๋” ๋ณต์žก์„ฑ๋งŒ ๋†’์—ฌ ํ˜ผ๋ž€๊ณผ ์˜ค๋ฅ˜ ๊ฐ€๋Šฅ์„ฑ์„ ํ‚ค์šด๋‹ค.

์˜ต์…”๋„์„ ์ปฌ๋ ‰์…˜์˜ ํ‚ค, ๊ฐ’, ์›์†Œ๋‚˜ ๋ฐฐ์—ด์˜ ์›์†Œ๋กœ ์‚ฌ์šฉํ•˜๋Š”๊ฒŒ ์ ์ ˆํ•œ ์ƒํ™ฉ์€ ๊ฑฐ์˜ ์—†๋‹ค!

์˜ต์…”๋„์„ ์ธ์Šคํ„ด์Šค ํ•„๋“œ์— ์ €์žฅํ•ด๋‘๋Š”๊ฒŒ ํ•„์š”ํ•  ๋•Œ๊ฐ€ ์žˆ์„๊นŒ?

ํด๋ž˜์Šค๋ฅผ ๋งŒ๋“ค๋•Œ ์ธ์Šคํ„ด์Šค์˜ ํ•„๋“œ ์ค‘ ์ƒ๋‹น์ˆ˜๊ฐ€ ํ•„์ˆ˜๊ฐ€ ์•„๋‹ˆ๊ณ , ๊ทธ ํ•„๋“œ๋“ค์ด ๊ธฐ๋ณธํƒ€์ž…์ด๋ผ ๊ฐ’์ด ์—†์Œ์„ ๋‚˜ํƒ€๋‚ผ ๋ฐฉ๋ฒ•์ด ๋งˆ๋•…์น˜ ์•Š๋‹ค๋ฉด ํ•„๋“œ์˜ Getter ๋ฉ”์„œ๋“œ๋“ค์ด ์˜ต์…”๋„์„ ๋ฐ˜ํ™˜ํ•˜๋Š” ๊ฒƒ๋„ ์ข‹์€ ๋ฐฉ๋ฒ•์ด๋‹ค.

โš ๏ธ **GitHub.com Fallback** โš ๏ธ