item 31 Jung inchul - JAVA-JIKIMI/EFFECTIVE-JAVA3 GitHub Wiki

Effective Java 3e ์•„์ดํ…œ 31๋ฅผ ์š”์•ฝํ•œ ๋‚ด์šฉ ์ž…๋‹ˆ๋‹ค.

public class Stack<E> {
    public Stack();
    public void push(E e);
    public E pop();
    public boolean isEmpty();
    public void pushAll(Iterable<E> src) {
    for (E e : src)
        push(e);
    }
}

์ด ๋ฉ”์„œ๋“œ๋Š” ๊นจ๋—์ด ์ปดํŒŒ์ผ ๋˜์ง€๋งŒ ์™„๋ฒฝํ•˜์ง„ ์•Š๋‹ค. Integer๋Š” Number์˜ ํ•˜์œ„ ํƒ€์ž…์ด๋‹ˆ ์ž˜ ๋™์ž‘ํ•ด์•ผ ํ•  ๊ฒƒ ๊ฐ™๋‹ค.

Strack<Number> numberStack = new Stack<>();
Iterable<Integer> intergers = ...;
numberStack.pushAll(integers);

ํ•˜์ง€๋งŒ ์‹ค์ œ๋กœ๋Š” ๋‹ค์Œ์˜ ์˜ค๋ฅ˜ ๋ฉ”์‹œ์ง€๊ฐ€ ๋œฌ๋‹ค. ๋งค๊ฐœ๋ณ€์ˆ˜ํ™” ํƒ€์ž…์ด ๋ถˆ๊ณต๋ณ€์ด๊ธฐ ๋•Œ๋ฌธ์ด๋‹ค.

StackTest.java:7: error: incompatible types: Iterable<Integer>
cannot be converted to Iterable<Number>
    numberStack.pushAll(integers);
                        ^

์ž๋ฐ”๋Š” ์ด๋Ÿฐ ์ƒํ™ฉ์— ๋Œ€์ฒ˜ํ•  ์ˆ˜ ์žˆ๋Š” ํ•œ์ •์  ์™€์ผ๋“œ์นด๋“œ ํƒ€์ž…์ด๋ผ๋Š” ํŠน๋ณ„ํ•œ ๋งค๊ฐœ๋ณ€์ˆ˜ํ™” ํƒ€์ž…์„ ์ง€์›ํ•œ๋‹ค. pushAll์˜ ์ž…๋ ฅ ๋งค๊ฐœ๋ณ€์ˆ˜ ํƒ€์ž…์€ 'E์˜ Iterable'์ด ์•„๋‹ˆ๋ผ 'E์˜ ํ•˜์œ„ ํƒ€์ž…์˜ Iterable'์ด์–ด์•ผ ํ•˜๋ฉฐ, ์™€์ผ๋“œ์นด๋“œ ํƒ€์ž… Iterable<? extends E>๊ฐ€ ์ •ํ™•ํžˆ ์ด๋Ÿฐ ๋œป์ด๋‹ค.

public void pushAll(Iterable<? extends E> src) {
    for (E e : src)
        push(e);
}

๊ธฐ๋Šฅ ํ™•์žฅ์œผ๋กœ ์•„๋ž˜์™€ ๊ฐ™์€ ๋ฉ”์†Œ๋“œ๊ฐ€ ์ถ”๊ฐ€๋˜์—ˆ๋‹ค.

public void popAll(Collection<E> dst) {
    when (!isEmpty())
    dst.add(pop())
}

๊ทธ๋ฆฌ๊ณ  ํด๋ผ์ด์–ธํŠธ์—์„œ ๋‹ค์Œ๊ณผ ๊ฐ™์€ ์˜ˆ๋ฅผ ์‹คํ–‰ํ•œ๋‹ค๋ฉด ์–ด๋–ป๊ฒŒ ํ•ด๊ฒฐํ•  ์ˆ˜ ์žˆ์„๊นŒ?

Strack<Number> numberStack = new Stack<>();
Iterable<Object> objects = ...;
numberStack.popAll(objects);

์ด ํด๋ผ์ด์–ธํŠธ ์ฝ”๋“œ๋ฅผ ์•ž์˜ popAll ์ฝ”๋“œ์™€ ํ•จ๊ป˜ ์ปดํŒŒ์ผํ•˜๋ฉด "Collection๋Š” Collection์˜ ํ•˜์œ„ ํƒ€์ž…์ด ์•„๋‹ˆ๋‹ค"๋ผ๋Š” ๋น„์Šทํ•œ ์˜ค๋ฅ˜๊ฐ€ ๋ฐœ์ƒํ•œ๋‹ค.

์ด๋ฒˆ์—๋„ ์™€์ผ๋“œ์นด๋“œ ํƒ€์ž…์œผ๋กœ ํ•ด๊ฒฐํ•  ์ˆ˜ ์žˆ๋‹ค.

public void popAll(Collection<? super E> dst) {
    when (!isEmpty())
    dst.add(pop())
}

์œ ์—ฐ์„ฑ์„ ๊ทน๋Œ€ํ™”ํ•˜๋ ค๋ฉด ์›์†Œ์˜ ์ƒ์‚ฐ์ž๋‚˜ ์†Œ๋น„์ž์šฉ ์ž…๋ ฅ ๋งค๊ฐœ๋ณ€์ˆ˜์— ์™€์ผ๋“œ์นด๋“œ ํƒ€์ž…์„ ์‚ฌ์šฉํ•˜๋ผ ํ•œํŽธ, ์ž…๋ ฅ ๋งค๊ฐœ๋ณ€์ˆ˜๊ฐ€ ์ƒ์‚ฐ์ž์™€ ์†Œ๋น„์ž ์—ญํ• ์„ ๋™์‹œ์— ํ•œ๋‹ค๋ฉด ์™€์ผ๋“œ์นด๋“œ ํƒ€์ž…์„ ์จ๋„ ์ข‹์„ ๊ฒŒ ์—†๋‹ค.

๋‹ค์Œ ๊ณต์‹์„ ์™ธ์›Œ๋‘๋ฉด ์–ด๋–ค ์™€์ผ๋“œ์นด๋“œ ํƒ€์ž…์„ ์จ์•ผ ํ•˜๋Š”์ง€ ๊ธฐ์–ตํ•˜๋Š” ๋ฐ ๋„์›€์ด ๋  ๊ฒƒ์ด๋‹ค.

ํŒฉ์Šค(PECS) : producer-extends, consumer-super

์ฆ‰, ๋งค๊ฐœ๋ณ€์ˆ˜ํ™” ํƒ€์ž… T๊ฐ€ ์ƒ์‚ฐ์ž๋ผ๋ฉด <? extends T>๋ฅผ ์‚ฌ์šฉํ•˜๊ณ , ์†Œ๋น„์ž๋ผ๋ฉด <? super T>๋ฅผ ์‚ฌ์šฉํ•˜๋ผ. ์ด์ „์˜ ์˜ˆ์ฒ˜๋Ÿผ pushAll์€ Stack์ด ์‚ฌ์šฉํ•  E ์ธ์Šคํ„ด์Šค๋ฅผ ์ƒ์‚ฐํ•˜๊ณ  popAll์€ Stack์ด E ์ธ์Šคํ„ด์Šค๋ฅผ ์†Œ๋น„ํ•˜๋Š” ์ชฝ์— ์†ํ•œ๋‹ค.

๊ทธ๋ ‡๋‹ค๋ฉด ์•„๋ž˜์™€ ๊ฐ™์€ ๋ฉ”์†Œ๋“œ๋Š” ์–ด๋–ป๊ฒŒ ์ˆ˜์ •ํ•ด์•ผ ํ• ๊นŒ?

public static <E> Set<E> union(Set<E> s1, Set<E> s2)

s1๊ณผ s2 ๋ชจ๋‘ E์˜ ์ƒ์‚ฐ์ž์ด๋‹ˆ PECS ๊ณต์‹์— ๋”ฐ๋ผ ๋‹ค์Œ์ฒ˜๋Ÿผ ์„ ์–ธํ•ด์•ผ ํ•œ๋‹ค.

public static <E> Set<E> union(Set<? extends E> s1, Set<? extends E> s2)

๊ทธ๋ ‡๋‹ค๋ฉด ํด๋ผ์ด์–ธํŠธ์—์„œ ์•„๋ž˜์™€ ๊ฐ™์ด ๋ฉ”์†Œ๋“œ๋ฅผ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋‹ค.

Set<Integer> integers = Set.of(1,3,5);
Set<Double> doubles = Set.of(2.0, 4.0, 6.0);
Set<Number> numbers = union(integers, doubles);

์•ž์˜ ์ฝ”๋“œ๋Š” ์ž๋ฐ”8๋ถ€ํ„ฐ ์ œ๋Œ€๋กœ ์ปดํŒŒ์ผ๋œ๋‹ค. ์ž๋ฐ”7๊นŒ์ง€๋Š” ์ด ์ฝ”๋“œ๋ฅผ ์ปดํŒŒ์ผํ•˜๋ฉด ์˜ค๋ฅ˜ ๋ฉ”์‹œ์ง€๋ฅผ ๋ณด๊ฒŒ ๋  ๊ฒƒ์ด๋‹ค.

Union.java:14: error: incompatible types
    Set<Number> numbers = union(integers, doubles);
                               ^
required: Set<Number>
found: Set<INT#1>
where INT#1, INT#2 are intersection types:
    INT#1 extends Number, Comparable<? extends INT#2>
    INT#2 extends Number, Comparable<?>

๊ทธ๋ ‡๋‹ค๋ฉด ์ž๋ฐ”7๊นŒ์ง€๋Š” ์–ด๋–ป๊ฒŒ ํ•ด๊ฒฐํ•  ์ˆ˜ ์žˆ์„๊นŒ?

์ปดํŒŒ์ผ๋Ÿฌ๊ฐ€ ์˜ฌ๋ฐ”๋ฅธ ํƒ€์ž…์„ ์ถ”๋ก ํ•˜์ง€ ๋ชปํ•  ๋•Œ๋ฉด ์–ธ์ œ๋“  ๋ช…์‹œ์  ํƒ€์ž… ์ธ์ˆ˜๋ฅผ ์‚ฌ์šฉํ•ด์„œ ํƒ€์ž…์„ ์•Œ๋ ค์ฃผ๋ฉด ๋œ๋‹ค.

Set<Number> numbers = Union.<Number>union(integers, doubles);

ํƒ€์ž… ๋งค๊ฐœ๋ณ€์ˆ˜์™€ ์™€์ผ๋“œ์นด๋“œ์—๋Š” ๊ณตํ†ต๋˜๋Š” ๋ถ€๋ถ„์ด ์žˆ์–ด์„œ, ๋ฉ”์„œ๋“œ๋ฅผ ์ •์˜ํ•  ๋•Œ ๋‘˜ ์ค‘ ์–ด๋Š ๊ฒƒ์„ ์‚ฌ์šฉํ•ด๋„ ๊ดœ์ฐฎ์„ ๋•Œ๊ฐ€ ๋งŽ๋‹ค. ์˜ˆ๋ฅผ ๋“ค์–ด ์ฃผ์–ด์ง„ ๋ฆฌ์ŠคํŠธ์—์„œ ๋ช…์‹œํ•œ ๋‘ ์ธ๋ฑ์Šค์˜ ์•„์ดํ…œ๋“ค์„ ๊ตํ™˜(swap)ํ•˜๋Š” ์ •์  ๋ฉ”์„œ๋“œ๋ฅผ ๋‘ ๋ฐฉ์‹ ๋ชจ๋‘๋กœ ์ •์˜ ํ•ด๋ณด์ž.

public static <E> void swap(List<E> list, int i, int j);
public static void swap(List<?> list, int i, int j);

์–ด๋–ค ์„ ์–ธ์ด ๋‚˜์„๊นŒ?

public API๋ผ๋ฉด ๊ฐ„๋‹จํ•œ ๋‘ ๋ฒˆ์งธ๊ฐ€ ๋‚ซ๋‹ค. ์–ด๋–ค ๋ฆฌ์ŠคํŠธ๋“  ์ด ๋ฉ”์„œ๋“œ์— ๋„˜๊ธฐ๋ฉด ๋ช…์‹œํ•œ ์ธ๋ฑ์Šค์˜ ์›์†Œ๋“ค์„ ๊ตํ™˜ํ•ด ์ค„ ๊ฒƒ์ด๋‹ค.

๋ฉ”์„œ๋“œ ์„ ์–ธ์— ํƒ€์ž… ๋งค๊ฐœ๋ณ€์ˆ˜๊ฐ€ ํ•œ ๋ฒˆ๋งŒ ๋‚˜์˜ค๋ฉด ์™€์ผ๋“œ์นด๋“œ๋กœ ๋Œ€์ฒดํ•˜๋ผ.

์ด๋•Œ ๋น„ํ•œ์ •์  ํƒ€์ž… ๋งค๊ฐœ๋ณ€์ˆ˜๋ผ๋ฉด ๋น„ํ•œ์ •์  ์™€์ผ๋“œ์นด๋“œ๋กœ ๋ฐ”๊พธ๊ณ , ํ•œ์ •์  ํƒ€์ž… ๋งค๊ฐœ๋ณ€์ˆ˜๋ผ๋ฉด ํ•œ์ •์  ์™€์ผ๋“œ ์นด๋“œ๋กœ ๋ฐ”๊พธ๋ฉด ๋œ๋‹ค.

ํ•˜์ง€๋งŒ ์•„๋ž˜ ์ฝ”๋“œ๋Š” ์ปดํŒŒ์ผํ•˜๋ฉด ๊ทธ๋‹ค์ง€ ๋„์›€์ด ๋˜์ง€ ์•Š๋Š” ์˜ค๋ฅ˜ ๋ฉ”์‹œ์ง€๊ฐ€ ๋‚˜์˜จ๋‹ค.

public static void swap(List<?> list, int i, int j) {
    list.set(i, list.set(j, list.get(i));
}

์›์ธ์€ ๋ฆฌ์ŠคํŠธ์˜ ํƒ€์ž…์ด List<?>์ธ๋ฐ, List<?>์—๋Š” null ์™ธ์—๋Š” ์–ด๋–ค ๊ฐ’๋„ ๋„ฃ์„ ์ˆ˜ ์—†๋‹ค๋Š” ๋ฐ ์žˆ๋‹ค. ๋‹คํ–‰ํžˆ (๋Ÿฐํƒ€์ž„ ์˜ค๋ฅ˜๋ฅผ ๋‚ผ ๊ฐ€๋Šฅ์„ฑ์ด ์žˆ๋Š”) ํ˜•๋ณ€ํ™˜์ด๋‚˜ ๋ฆฌ์ŠคํŠธ์˜ ๋กœ ํƒ€์ž…์„ ์‚ฌ์šฉํ•˜์ง€ ์•Š๊ณ ๋„ ํ•ด๊ฒฐํ•  ๋ฐฉ๋ฒ•์ด ์žˆ๋‹ค. ๋ฐ”๋กœ ์™€์ผ๋“œ์นด๋“œ ํƒ€์ž…์˜ ์‹ค์ œ ํƒ€์ž…์„ ์•Œ๋ ค์ฃผ๋Š” ๋ฉ”์„œ๋“œ๋ฅผ private ๋„์šฐ๋ฏธ ๋ฉ”์„œ๋“œ๋กœ ๋”ฐ๋กœ ์ž‘์„ฑํ•˜์—ฌ ํ™œ์šฉํ•˜๋Š” ๋ฐฉ๋ฒ•์ด๋‹ค.

public static void swap(List<?> list, int i, int j) {
    swapHelper(i, list.set(j, list.get(i));
}
public static <E> void swapHelper(List<E> list, int i, int j) {
    list.set(i, list.set(j, list.get(i));
}

์ •๋ฆฌ

์กฐ๊ธˆ ๋ณต์žกํ•˜๋”๋ผ๋„ ์™€์ผ๋“œ์นด๋“œ ํƒ€์ž…์„ ์ ์šฉํ•˜๋ฉด API๊ฐ€ ํ›จ์”ฌ ์œ ์—ฐํ•ด์ง„๋‹ค. ๊ทธ๋Ÿฌ๋‹ˆ ๋„๋ฆฌ ์“ฐ์ผ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๋ฅผ ์ž‘์„ฑํ•œ๋‹ค๋ฉด ๋ฐ˜๋“œ์‹œ ์™€์ผ๋“œ์นด๋“œ ํƒ€์ž…์„ ์ ์ ˆํžˆ ์‚ฌ์šฉํ•ด์ค˜์•ผ ํ•œ๋‹ค. PECS ๊ณต์‹์„ ๊ธฐ์–ตํ•˜์ž. ์ฆ‰, ์ƒ์‚ฐ์ž(producer)๋Š” extends๋ฅผ ์†Œ๋น„์ž(consumer)๋Š” super๋ฅผ ์‚ฌ์šฉํ•œ๋‹ค. Comparable๊ณผ Comparator๋Š” ๋ชจ๋‘ ์†Œ๋น„์ž๋ผ๋Š” ์‚ฌ์‹ค๋„ ์žŠ์ง€ ๋ง์ž

์ฐธ๊ณ 

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