item 47 JihoonKim - JAVA-JIKIMI/EFFECTIVE-JAVA3 GitHub Wiki

[item47] ๋ฐ˜ํ™˜ ํƒ€์ž…์œผ๋กœ๋Š” ์ŠคํŠธ๋ฆผ๋ณด๋‹ค ์ปฌ๋ ‰์…˜์ด ๋‚ซ๋‹ค

์ผ๋ จ์˜ ์›์†Œ(์›์†Œ ์‹œํ€€์Šค)๋ฅผ ๋ฆฌํ„ดํ•  ๋•Œ์˜ ํƒ€์ž…

  • Collection, Set, List ๊ฐ™์€ ์ปฌ๋ ‰์…˜ ์ธํ„ฐํŽ˜์ด์Šค(๊ธฐ๋ณธ)
  • Iterable
  • ๋ฐฐ์—ด(์„ฑ๋Šฅ์— ๋ฏผ๊ฐํ•œ ์ƒํ™ฉ)
  • ์ŠคํŠธ๋ฆผ

์ŠคํŠธ๋ฆผ์ด ๋„์ž…๋˜๋ฉด์„œ ๋ฆฌํ„ด ํƒ€์ž…์˜ ์„ ํƒ์ด ๋ณต์žกํ•ด์กŒ๋‹ค.

์ŠคํŠธ๋ฆผ์˜ ๋ฐ˜๋ณต ์ง€์›

์ŠคํŠธ๋ฆผ์€ Iterable์„ ํ™•์žฅ(extends)ํ•˜์ง€ ์•Š์•„ ๋ฐ˜๋ณต(iteration)์„ ์ง€์›ํ•˜์ง€ ์•Š๋Š”๋‹ค. ๋”ฐ๋ผ์„œ, ์ŠคํŠธ๋ฆผ๊ณผ ๋ฐ˜๋ณต์„ ์•Œ๋งž๊ฒŒ ์กฐํ•ฉํ•ด์•ผ ์ข‹์€ ์ฝ”๋“œ๊ฐ€ ๋‚˜์˜จ๋‹ค.

// Stream์˜ iterator ๋ฉ”์„œ๋“œ์— ๋ฉ”์„œ๋“œ ์ฐธ์กฐ๋ฅผ ๊ฑด๋„ค ์ŠคํŠธ๋ฆผ์˜ ๋ฐ˜๋ณต์„ ์ง€์› - Compile ์—๋Ÿฌ(ํƒ€์ž… ์ถ”๋ก  ํ•œ๊ณ„)
for (ProcessHandle p : ProcessHandle.allProcesses()::iterator) { 
	// process ์ฒ˜๋ฆฌ
}

// Stream์˜ iterator ๋ฉ”์„œ๋“œ์— ๋ฉ”์„œ๋“œ ์ฐธ์กฐ๋ฅผ ๊ฑด๋„ค์–ด ์ŠคํŠธ๋ฆผ์˜ ๋ฐ˜๋ณต์„ ์ง€์› - ์ŠคํŠธ๋ฆผ ๋ฐ˜๋ณต์„ ์œ„ํ•œ '๋”์ฐํ•œ' ์šฐํšŒ ๋ฐฉ๋ฒ•
for (ProcessHandle p : (Iterable<ProcessHandle>) ProcessHandle.allProcesses()::iterator) {
	// process ์ฒ˜๋ฆฌ
}

์–ด๋Œ‘ํ„ฐ ๋ฉ”์„œ๋“œ ์ž‘์„ฑ์„ ํ†ตํ•ด ๊ฐœ์„  ๊ฐ€๋Šฅํ•˜๋‹ค.

// Stream<E>๋ฅผ Iterable<E>๋กœ ์ค‘๊ฐœํ•ด์ฃผ๋Š” ์–ด๋Œ‘ํ„ฐ
public static <E> Iterable<E> iterableOf(Stream<E> stream) {
	return stream::iterator;
}

for (ProcessHandle p : iterableOf(ProcessHandle.allProcesses())) {
	// process ์ฒ˜๋ฆฌ
}
// Iterable<E>๋ฅผ Stream<E>๋กœ ์ค‘๊ฐœํ•ด์ฃผ๋Š” ์–ด๋Œ‘ํ„ฐ
public static <E> Stream<E> streamOf(Iterable<E> iterable) {
	return StreamSupport.stream(iterable.spliterator(), false); // 2nd param์€ parallel ์—ฌ๋ถ€
}

๊ณต๊ฐœ API๋ฅผ ์ž‘์„ฑํ•œ๋‹ค๋ฉด ์ŠคํŠธ๋ฆผ ํŒŒ์ดํ”„๋ผ์ธ ์‚ฌ์šฉ์ž์™€ ๋ฐ˜๋ณต๋ฌธ ์‚ฌ์šฉ์ž ๋ชจ๋‘๋ฅผ ๋ฐฐ๋ คํ•ด์•ผ ํ•œ๋‹ค.

์ผ๋ฐ˜์ ์œผ๋กœ Collection ๋˜๋Š” ๊ทธ ํ•˜์œ„ ํƒ€์ž…์„ ์“ฐ๋Š” ๊ฒŒ ์ตœ์„ ์ด๋‹ค.

Collection ์ธํ„ฐํŽ˜์ด์Šค๋Š” Iterable์˜ ํ•˜์œ„ ํƒ€์ž…์ด๊ณ  stream ๋ฉ”์„œ๋“œ๋„ ์ œ๊ณตํ•˜๋‹ˆ ๋ฐ˜๋ณต๊ณผ ์ŠคํŠธ๋ฆผ์„ ๋™์‹œ์— ์ง€์›ํ•œ๋‹ค.
๋”ฐ๋ผ์„œ, ์›์†Œ ์‹œํ€€์Šค๋ฅผ ๋ฆฌํ„ดํ•˜๋Š” ๊ณต๊ฐœ API์˜ ๋ฆฌํ„ด ํƒ€์ž…์—๋Š” ์ผ๋ฐ˜์ ์œผ๋กœ Collection ๋˜๋Š” ๊ทธ ํ•˜์œ„ ํƒ€์ž…์„ ์“ฐ๋Š” ๊ฒŒ ์ตœ์„ ์ด๋‹ค.
ํ•˜์ง€๋งŒ, ๋‹จ์ง€ ์ปฌ๋ ‰์…˜์„ ๋ฆฌํ„ดํ•œ๋‹ค๋Š” ์ด์œ ๋กœ ๋ฉ์น˜ ํฐ ์‹œํ€€์Šค๋ฅผ ๋ฉ”๋ชจ๋ฆฌ์— ์˜ฌ๋ ค์„œ๋Š” ์•ˆ ๋œ๋‹ค.

๋ฆฌํ„ดํ•  ์‹œํ€€์Šค๊ฐ€ ํฌ์ง€๋งŒ ํ‘œํ˜„์„ ๊ฐ„๊ฒฐํ•˜๊ฒŒ ํ•  ์ˆ˜ ์žˆ๋‹ค๋ฉด ์ „์šฉ Collection์„ ๊ตฌํ˜„ํ•˜๋Š” ๋ฐฉ์•ˆ๋„ ์ƒ๊ฐํ•ด๋ณด์ž.

์ „์šฉ Collection ์˜ˆ์ œ

์ฃผ์–ด์ง„ ์ง‘ํ•ฉ์˜ ๋ฉฑ์ง‘ํ•ฉ(ํ•œ ์ง‘ํ•ฉ์˜ ๋ชจ๋“  ๋ถ€๋ถ„์ง‘ํ•ฉ์„ ์›์†Œ๋กœ ํ•˜๋Š” ์ง‘ํ•ฉ)์„ ๋ฆฌํ„ดํ•˜๋Š” ์ƒํ™ฉ
์›์†Œ ๊ฐœ์ˆ˜๊ฐ€ n๊ฐœ ์ด๋ฉด ๋ฉฑ์ง‘ํ•ฉ์˜ ์›์†Œ ๊ฐœ์ˆ˜๋Š” 2^n๊ฐœ(์ง€์ˆ˜๋ฐฐ๋กœ ์ฆ๊ฐ€)

์ฐธ๊ณ ) {a, b, c}์˜ ๋ฉฑ์ง‘ํ•ฉ์€ { {}, {a}, {b}, {c}, {a, b}, {a, c}, {b, c}, {a, b, c} }

AbstractList๋ฅผ ์ด์šฉํ•˜์—ฌ ์ปฌ๋ ‰์…˜ ๊ตฌํ˜„

  • ๊ฐ ์›์†Œ์˜ ์ธ๋ฑ์Šค๋ฅผ ๋น„ํŠธ๋ฒกํ„ฐ๋กœ ์‚ฌ์šฉ(n๋ฒˆ์งธ ๋น„ํŠธ ๊ฐ’์€ ํ•ด๋‹น ์›์†Œ๊ฐ€ n๋ฒˆ์งธ ์›์†Œ ํฌํ•จ ์—ฌ๋ถ€)
  • 0๋ถ€ํ„ฐ 2^n - 1 ๊นŒ์ง€์˜ ์ด์ง„์ˆ˜์™€์˜ ๋งคํ•‘
public class PowerSet {
    public static final <E> Collection<Set<E>> of(Set<E> s) {
       List<E> src = new ArrayList<>(s);
       if(src.size() > 30) { // Collection์„ ๋ฆฌํ„ด ํƒ€์ž…์œผ๋กœ ์“ธ ๋•Œ์˜ ๋‹จ์ 
           throw new IllegalArgumentException("์ง‘ํ•ฉ์— ์›์†Œ๊ฐ€ ๋„ˆ๋ฌด ๋งŽ์Šต๋‹ˆ๋‹ค(์ตœ๋Œ€ 30๊ฐœ).: " + s);
       }

       return new AbstractList<Set<E>>() {
           @Override
           public int size() {
               return 1 << src.size(); // 2^n
           }

           @Override
           public boolean contains(Object o) {
               return o instanceof Set && src.containsAll((Set) o);
           }

           @Override
           public Set<E> get(int index) {
               Set<E> result = new HashSet<>();
               for (int i = 0; index != 0; i++, index >>=1) {
                   if((index & 1) == 1) {
                       result.add(src.get(i));
                   }
               }
               return result;
           }
       };
    }
}

AbstractCollection์„ ํ™œ์šฉํ•˜์—ฌ Collection ๊ตฌํ˜„์ฒด๋ฅผ ์ž‘์„ฑํ•  ๋•Œ๋Š” Iterable์šฉ ๋ฉ”์„œ๋“œ ์™ธ์˜ contains์™€ size๋งŒ ๋” ๊ตฌํ˜„ํ•˜๋ฉด ๋œ๋‹ค.
contains์™€ size๋ฅผ ๊ตฌํ˜„ํ•˜๋Š” ๊ฒŒ ๋ถˆ๊ฐ€๋Šฅํ•˜๋‹ค๋ฉด ์ปฌ๋ ‰์…˜๋ณด๋‹ค๋Š” ์ŠคํŠธ๋ฆผ์ด๋‚˜ Iterable์„ ๋ฆฌํ„ดํ•˜๋Š” ํŽธ์ด ๋‚ซ๋‹ค(๋ณ„๋„์˜ ๋ฉ”์„œ๋“œ๋ฅผ ๋ถ€์–ด ๋‘ ๋ฐฉ์‹ ๋ชจ๋‘ ์ œ๊ณตํ•ด๋„ ๋œ๋‹ค).

์ž…๋ ฅ ๋ฆฌ์ŠคํŠธ์˜ ๋ชจ๋“  ๋ถ€๋ถ„๋ฆฌ์ŠคํŠธ๋ฅผ ์ŠคํŠธ๋ฆผ์œผ๋กœ ๋ฆฌํ„ด ์˜ˆ์ œ

๋ถ€๋ถ„ ๋ฆฌ์ŠคํŠธ๋ฅผ ๊ตฌํ•˜๋Š” ๋ฐฉ๋ฒ•

  • (a, b, c)์˜ prefixes - (a), (a, b), (a, b, c)
  • (a, b, c)์˜ suffixes - (c), (b, c), (a, b, c)
  • ๋นˆ ๋ฆฌ์ŠคํŠธ(empty list)
public class SubList {
    public static <E> Stream<List<E>> of(List<E> list) {
        return Stream.concat(Stream.of(Collections.emptyList()),			// ๋นˆ ๋ฆฌ์ŠคํŠธ
                             prefixes(list).flatMap(SubList::suffixes));
    }

    public static <E> Stream<List<E>> prefixes(List<E> list) {
        return IntStream.rangeClosed(1, list.size())
                        .mapToObj(end -> list.subList(0, end));
    }

    public static <E> Stream<List<E>> suffixes(List<E> list) {
        return IntStream.rangeClosed(0, list.size())
                        .mapToObj(start -> list.subList(start, list.size()));
    }
}
public static <E> Stream<List<E>> of(List<E> list) {
	return IntStream.range(0, list.size())
		.mapToObj(start -> 
			IntStream.rangeClosed(start + 1, list.size())
				.mapToObj(end -> list.subList(start, end)))
		.flatMap(x -> x);
}

์ŠคํŠธ๋ฆผ ๋ฆฌํ„ด๋งŒ ์ œ๊ณต๋˜๋‹ˆ ๋ฐ˜๋ณต๋ฌธ ์‚ฌ์šฉ์ด ํ•„์š”ํ•  ๋•Œ์—๋Š” Iterable๋กœ ๋ณ€ํ™˜ํ•ด์ฃผ๋Š” ์–ด๋Œ‘ํ„ฐ๋ฅผ ์ด์šฉํ•ด์•ผ ํ•œ๋‹ค. (์ฝ”๋“œ๊ฐ€ ์–ด์ˆ˜์„ ํ•ด์ง€๊ณ , ์ž‘๊ฐ€ ์ปดํ“จํ„ฐ๋กœ 2.3๋ฐฐ ๋” ๋Š๋ฆฌ๋‹ค.) (์ฑ…์—๋Š” ์•ˆ ๋‚˜์˜จ) ์ง์ ‘ ๊ตฌํ˜„ํ•œ Collection์ด ์ŠคํŠธ๋ฆผ๋ณด๋‹ค 1.4๋ฐฐ(์ž‘๊ฐ€ ์ปดํ“จํ„ฐ) ๋นจ๋ž๋‹ค(์ฝ”๋“œ๋Š” ๋” ์ง€์ €๋ถ„ํ•ด์กŒ๋‹ค).

ํ•ต์‹ฌ ์ •๋ฆฌ

  • ์›์†Œ ์‹œํ€€์Šค๋ฅผ ๋ฆฌํ„ดํ•˜๋Š” ๋ฉ”์„œ๋“œ๋ฅผ ์ž‘์„ฑํ•  ๋•Œ ์ŠคํŠธ๋ฆผ ์‚ฌ์šฉ์ž์™€ ๋ฐ˜๋ณต๋ฌธ ์‚ฌ์šฉ์ž๊ฐ€ ๋ชจ๋‘ ์žˆ์„ ์ˆ˜ ์žˆ๊ธฐ์— ์–‘์ชฝ์„ ๋งŒ์กฑ์‹œํ‚ค๋ ค๊ณ  ๋…ธ๋ ฅํ•˜์ž
  • ์ปฌ๋ ‰์…˜์„ ๋ฆฌํ„ดํ•  ์ˆ˜ ์žˆ๋‹ค๋ฉด ์ปฌ๋ ‰์…˜์„ ์ด์šฉํ•˜์ž
    • ์›์†Œ ๊ฐœ์ˆ˜๊ฐ€ ์ ๊ฑฐ๋‚˜ ์ด๋ฏธ ์ปฌ๋ ‰์…˜์— ๋‹ด์•„ ๊ด€๋ฆฌํ•˜๊ณ  ์žˆ์œผ๋ฉด ํ‘œ์ค€ ์ปฌ๋ ‰์…˜(E.g ArrayList)์„ ์ด์šฉํ•˜์ž
    • ๊ทธ ์™ธ์—๋Š” ์ „์šฉ ์ปฌ๋ ‰์…˜(E.g ๋ฉฑ์ง‘ํ•ฉ)์„ ๊ตฌํ˜„ํ•˜๋Š” ๊ฒƒ์„ ๊ณ ๋ คํ•˜์ž
  • ์ปฌ๋ ‰์…˜์„ ๋ฆฌํ„ดํ•  ์ˆ˜ ์—†๋‹ค๋ฉด ์ŠคํŠธ๋ฆผ์ด๋‚˜ Iterable ์ค‘ ๋” ๋‚˜์€ ๊ฒƒ์„ ์ด์šฉํ•˜์ž
  • ๋งŒ์•ฝ ๋‚˜์ค‘์— Stream ์ธํ„ฐํŽ˜์ด์Šค๊ฐ€ Iterable์„ ์ง€์›ํ•˜๋„๋ก ์ˆ˜์ •๋œ๋‹ค๋ฉด, ์ŠคํŠธ๋ฆผ ์ฒ˜๋ฆฌ์™€ ๋ฐ˜๋ณต์— ๋ชจ๋‘ ์‚ฌ์šฉ ๊ฐ€๋Šฅํ•˜๋‹ˆ ์•ˆ์‹ฌํ•˜๊ณ  ์ŠคํŠธ๋ฆผ์„ ๋ฆฌํ„ดํ•˜๋ฉด ๋  ๊ฒƒ์ด๋‹ค.
โš ๏ธ **GitHub.com Fallback** โš ๏ธ