[์ดํŽ™ํ‹ฐ๋ธŒ ์ž๋ฐ”] Item31. ํ•œ์ •์  ์™€์ผ๋“œ์นด๋“œ๋ฅผ ์‚ฌ์šฉํ•ด API์˜ ์œ ์—ฐ์„ฑ์„ ๋†’์ด๋ผ.

2023. 3. 22. 14:03ใ†JAVA/Effective JAVA

728x90

 

 

[์ดํŽ™ํ‹ฐ๋ธŒ ์ž๋ฐ”] Item31. ํ•œ์ •์  ์™€์ผ๋“œ์นด๋“œ๋ฅผ ์‚ฌ์šฉํ•ด API์˜ ์œ ์—ฐ์„ฑ์„ ๋†’์ด๋ผ.

 

 

 

1๏ธโƒฃ Chooser์™€ Union API ๊ฐœ์„ 

public class Stack<E> {
    private E[] elements;
    private int size = 0;
    private static final int DEFAULT_INITIAL_CAPACITY = 16;

    @SuppressWarnings("unchecked")
    public Stack() {
        elements = (E[]) new Object[DEFAULT_INITIAL_CAPACITY];
    }

    public void push(E e) {
        ensureCapacity();
        elements[size++] = e;
    }

    public E pop() {
        if (size == 0) {
            throw new EmptyStackException();
        }

        E result = elements[--size];
        elements[size] = null;
        return result;
    }

    public boolean isEmpty() {
        return size == 0;
    }

    // ์™€์ผ๋“œ์นด๋“œ ํƒ€์ž…์„ ์‚ฌ์šฉํ•˜์ง€ ์•Š์€ pushAll ๋ฉ”์„œ๋“œ -> ๊ฒฐํ•จ์ด ์žˆ๋‹ค!
//    public void pushAll(Iterable<E> src) {
//        for (E e : src) {
//            push(e);
//        }
//    }

    // ์ƒ์‚ฐ์ž(producer) ๋งค๊ฐœ๋ณ€์ˆ˜์— ์™€์ผ๋“œ์นด๋“œ ํƒ€์ž… ์ ์šฉ
    public void pushAll(Iterable<? extends E> src) {
        for (E e : src) {
            push(e);
        }
    }

    // ์™€์ผ๋“œ์นด๋“œ ํƒ€์ž…์„ ์‚ฌ์šฉํ•˜์ง€ ์•Š์€ popAll ๋ฉ”์„œ๋“œ -> ๊ฒฐํ•จ์ด ์žˆ๋‹ค!
//    public void popAll(Collection<E> dst) {
//        while (!isEmpty()) {
//            dst.add(pop());
//        }
//    }

    // ์†Œ๋น„์ž(consumer) ๋งค๊ฐœ๋ณ€์ˆ˜์— ์™€์ผ๋“œ์นด๋“œ ํƒ€์ž… ์ ์šฉ
    public void popAll(Collection<? super E> dst) {
        while (!isEmpty()) {
            dst.add(pop());
        }
    }


    private void ensureCapacity() {
        if (elements.length == size) {
            elements = Arrays.copyOf(elements, 2 * size + 1);
        }
    }

    public static void main(String[] args) {
        Stack<Number> numberStack = new Stack<>();
        Iterable<Integer> integers = Arrays.asList(3, 1, 4, 1, 5, 9);
        numberStack.pushAll(integers);

        Iterable<Double> doubles = Arrays.asList(3.0, 1.0);
        numberStack.pushAll(doubles);

        Collection<Object> objects = new ArrayList<>();
        numberStack.popAll(objects);

        System.out.println("objects = " + objects);
    }
}

PECS

: Producer-Extends , Consumer-super

 

Producer-Extends

public void pushAll(Iterable<E> src) {
    for (E e : src) {
        push(e);
    }
}
Stack<Number> numberStack = new Stack<>();
Iterable<Integer> integers = Arrays.asList(3, 1, 4, 1, 5, 9);
numberStack.pushAll(integers);

ํ•œ์ •์  ์™€์ผ๋“œ์นด๋“ค๋ฅผ ์‚ฌ์šฉํ•˜์ง€ ์•Š์€ pushAll ๋ฉ”์„œ๋“œ์—์„œ๋Š” Iterable<Number> ๋งŒ ๋ฐ›์„ ์ˆ˜ ์žˆ๊ธฐ ๋•Œ๋ฌธ์— Iterable<Integer>๋ฅผ pushAll ํ•˜๋ ค๊ณ  ํ•˜๋ฉด ์—๋Ÿฌ๊ฐ€ ๋‚œ๋‹ค. 

๊ทธ๋Ÿฐ๋ฐ ์ƒ๊ฐํ•ด๋ณด๋ฉด Stack์˜ Number์— Integer ๋ฅผ ๋‹ด์•„๋„ ๊ดœ์ฑƒ๊ธฐ ๋•Œ๋ฌธ์—... ํ•œ์ •์  ์™€์ผ๋“œ ์นด๋“œ๋ฅผ ์‚ฌ์šฉํ•ด์„œ ์ข€ ๋” ์œ ์—ฐํ•˜๊ฒŒ ๋งŒ๋“ค ์ˆ˜ ์žˆ๋‹ค. 

 

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

์ด๋ ‡๊ฒŒ ? extends E ๋กœ ์„ ์–ธํ•˜๋ฉด Number๋ฅผ ์ƒ์†๋ฐ›๋Š” ์–ด๋–ค ํƒ€์ž…์ด๋“  ์™€๋„ ์ƒ๊ด€์—†๋‹ค๋Š” ๋œป์ด ๋˜๊ธฐ ๋•Œ๋ฌธ์— 

 

Stack<Number> numberStack = new Stack<>();
Iterable<Integer> integers = Arrays.asList(3, 1, 4, 1, 5, 9);
numberStack.pushAll(integers);

Iterable<Double> doubles = Arrays.asList(3.0, 1.0);
numberStack.pushAll(doubles);

Iterable<Integer>, Iterable<Double> ๋ชจ๋‘ pushAll ํ•  ์ˆ˜ ์žˆ๋‹ค. 

 

-> Producer-Extends ๋Š” Object ์ปฌ๋ ‰์…˜์— Number, Integer๋ฅผ ๋„ฃ์„ ์ˆ˜ ์žˆ๊ณ , Number์˜ ์ปฌ๋ ‰์…˜์— Integer๋ฅผ ๋„ฃ์„ ์ˆ˜ ์žˆ๋‹ค. 

 

 

Consumer-Super

public void popAll(Collection<E> dst) {
    while (!isEmpty()) {
        dst.add(pop());
    }
}
Collection<Object> objects = new ArrayList<>();
numberStack.popAll(objects);

ํ•œ์ •์  ์™€์ผ๋“œ์นด๋“œ ํƒ€์ž…์„ ์‚ฌ์šฉํ•˜์ง€ ์•Š์€ popAll ๋ฉ”์„œ๋“œ์— ๋Œ€ํ•ด์„œ Collection<Object>๋ฅผ numberStack์˜ popAll์— ๋„ฃ์œผ๋ ค๊ณ  ํ•˜๋ฉด ์—๋Ÿฌ๊ฐ€ ๋‚œ๋‹ค.

์™œ๋ƒํ•˜๋ฉด popAll์€ Collection<Number>๋งŒ ๋ฐ›์„ ์ˆ˜ ์žˆ๊ธฐ ๋•Œ๋ฌธ์ด๋‹ค..! 

๊ทผ๋ฐ Number์˜ ์ปฌ๋ ‰์…˜ ๊ฐ์ฒด๋ฅผ ๊บผ๋‚ด์„œ Object ์ปฌ๋ ‰์…˜์— ๋‹ด์•„๋„ ๋ฌธ์ œ ์—†๊ธฐ ๋•Œ๋ฌธ์— ์—ฌ๊ธฐ์„œ๋„ ํ•œ์ •์  ์™€์ผ๋“œ ์นด๋“œ๋ฅผ ์‚ฌ์šฉํ•˜๋ฉด ์ข€ ๋” ์œ ์—ฐํ•˜๊ฒŒ ๋งŒ๋“ค ์ˆ˜ ์žˆ๋‹ค. 

 

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

์ด๋ ‡๊ฒŒ <? super E> ๋กœ ๋งค๊ฐœ๋ณ€์ˆ˜ ํƒ€์ž…์„ ๋ฐ›์œผ๋ฉด E๋ณด๋‹ค ๋†’์€ ์ƒ์œ„ ํด๋ž˜์Šค๋ฅผ ๋งค๊ฐœ๋ณ€์ˆ˜๋กœ ๋ฐ›์„ ์ˆ˜ ์žˆ๋‹ค. 

 

-> Consumer-Super๋Š” Integer ์ปฌ๋ ‰์…˜์˜ ๊ฐ์ฒด๋ฅผ ๊บผ๋‚ด์„œ Number์˜ ์ปฌ๋ ‰์…˜์— ๋‹ด์„ ์ˆ˜ ์žˆ๊ณ , Number๋‚˜ Integer์˜ ์ปฌ๋ ‰์…˜์˜ ๊ฐ์ฒด๋ฅผ ๊บผ๋‚ด์„œ Object ์ปฌ๋ ‰์…˜์— ๋‹ด์„ ์ˆ˜ ์žˆ๋‹ค. 

 

 

public class Chooser<T> { // T ์ƒ์„ฑ์ž ๋งค๊ฐœ๋ณ€์ˆ˜์— ์™€์ผ๋“œ ์นด๋“œ ํƒ€์ž… ์ ์šฉ
    private final List<T> choiceList;
    private final Random rnd = new Random();

    // producer
    public Chooser(Collection<? extends T> choices) {
        choiceList = new ArrayList<>(choices);
    }

    public T choose() {
        return choiceList.get(rnd.nextInt(choiceList.size()));
    }

    public static void main(String[] args) {
        List<Integer> intList = List.of(1, 2, 3, 4, 5, 6);
        Chooser<Number> chooser = new Chooser<>(intList);
        for (int i = 0; i < 10; i++) {
            Number choose = chooser.choose();
            System.out.println("choose = " + choose);
        }
    }
}

Chooser์€ ๋ฐ›์•„์„œ ๋‹ด๊ณ  ์žˆ๊ธฐ ๋•Œ๋ฌธ์— Producer์ด๋‹ค. ๋”ฐ๋ผ์„œ <? extends T> ์ด๋‹ค. 

 

public class Union {
    // producer
    public static <E> Set<E> union(Set<? extends E> s1, Set<? extends E> s2) {
        Set<E> result = new HashSet<>(s1);
        result.addAll(s2);
        return result;
    }

    public static void main(String[] args) {
        Set<Integer> integers = new HashSet<>();
        integers.add(1);
        integers.add(3);
        integers.add(5);

        Set<Double> doubles = new HashSet<>();
        doubles.add(2.0);
        doubles.add(4.0);
        doubles.add(6.0);

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

        System.out.println("numbers = " + numbers);
    }

}

Union ์—ญ์‹œ ๋ฐ›์•„์„œ addAll ์ฆ‰, ๋‹ด๊ณ  ์žˆ๊ธฐ ๋•Œ๋ฌธ์— Producer๋กœ <? extends E> ์ด๋‹ค. 

 

 

 

2๏ธโƒฃ Comparator์™€ Comparable์€ ์†Œ๋น„์ž 

package chapter04.item31.example;

public class Box<T extends Comparable<T>> implements Comparable<Box<T>> {

    private final T value;

    public Box(T value) {
        this.value = value;
    }

    @SuppressWarnings("unchecked")
    @Override
    public int compareTo(Box o) {
        return this.value.compareTo((T) o.value);
    }

    @Override
    public String toString() {
        return "Box{" +
                "value=" + value +
                '}';
    }
}
package chapter04.item31.example;

public class IntegerBox extends Box<Integer> {

    private final String message;

    public IntegerBox(int value, String message) {
        super(value);
        this.message = message;
    }

    @Override
    public String toString() {
        return "IntegerBox{" +
                "message='" + message + '\'' +
                '}';
    }
}

public class RecursiveTypeBound { // ์™€์ผ๋“œ์นด๋“œ ํƒ€์ž… ํ•œ์ •์„ ์ด์šฉํ•ด ์ƒํ˜ธ ๋น„๊ตํ•  ์ˆ˜ ์žˆ์Œ์„ ํ‘œํ˜„ 

    // ์ปฌ๋ ‰์…˜์—์„œ ์ตœ๋Œ€๊ฐ’์„ ๋ฐ˜ํ™˜ํ•˜๋Š” ๋ฉ”์„œ๋“œ 
    public static <E extends Comparable<? super E>> E max(List< ? extends E> list) {
        if (list.isEmpty()) {
            throw new IllegalArgumentException("collection is empty");
        }

        E result = null;

        for (E e : list) {
            if (result == null || e.compareTo(result) > 0) {
                result = e;
            }
        }

        return result;
    }

    public static void main(String[] args) {
        List<IntegerBox> list = new ArrayList<>();
        list.add(new IntegerBox(1, "hyejin"));
        list.add(new IntegerBox(2, "park"));
        System.out.println("list = " + max(list));
    }
    
}

IntegerBox๋Š” Comparable์„ ์ง์ ‘ ๊ตฌํ˜„ํ•˜์ง€ ์•Š์•˜์ง€๋งŒ Box๋ฅผ ์ƒ์†๋ฐ›๊ณ  ์žˆ๋Š”๋ฐ ์ƒ์œ„ํƒ€์ž…์ธ Box๊ฐ€ Comparable์„ ๊ตฌํ˜„ํ•˜๊ณ  ์žˆ๋Š” ์ƒํƒœ์ด๋‹ค. 

-> ์ด๋•Œ Comparable์„ ์ง์ ‘ ๊ตฌํ˜„ํ•˜์ง€ ์•Š๊ณ , ์ง์ ‘ ๊ตฌํ˜„ํ•œ ๋‹ค๋ฅธ ํƒ€์ž…์„ ํ™•์žฅํ•œ ํƒ€์ž…์„ ์ง€์›ํ•˜๋ ค๋ฉด ํ•œ์ •์  ์™€์ผ๋“œ์นด๋“œ๊ฐ€ ํ•„์š”ํ•˜๋‹ค. 

 

 

 

๐Ÿ“– ์™€์ผ๋“œ์นด๋“œ ํ™œ์šฉ ํŒ 

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

    public static void main(String[] args) {
        List<String> argList = Arrays.asList(args);
        swap(argList, 0, argList.size() - 1);
        System.out.println("argList = " + argList);
    }
}
public class Swap {
    public static <E> void swap(List<E> list, int i, int j) {
        list.set(i, list.set(j, list.get(i)));
    }


    public static void main(String[] args) {
        List<String> argList = Arrays.asList(args);
        swap(argList, 0, argList.size() - 1);
        System.out.println("argList = " + argList);
    }
}

์œ„์˜ ์™€์ผ๋“œ์นด๋“œ๋ฅผ ์‚ฌ์šฉํ•œ ๊ฒฝ์šฐ์™€ ํŠน์ • ํƒ€์ž… ์„ ์‚ฌ์šฉํ•œ ๊ฒฝ์šฐ๋Š” ๊ฐ™๋‹ค๊ณ  ์ƒ๊ฐํ•  ์ˆ˜ ์žˆ์ง€๋งŒ ๋‹ค๋ฅด๋‹ค.

์œ„์˜ ?๋งŒ ์‚ฌ์šฉํ•œ ๊ฒฝ์šฐ๊ฐ€ ๋น„ํ•œ์ •์  ์™€์ผ๋“œ ์นด๋“œ๋กœ ์ •์˜ํ•œ ๊ฒƒ์ธ๋ฐ ์ด๋Š” null์„ ์ œ์™ธํ•œ ์•„๋ฌด๊ฒƒ๋„ ๋„ฃ์„ ์ˆ˜ ์—†๊ธฐ ๋•Œ๋ฌธ์— list.setํ•  ๋•Œ ์—๋Ÿฌ๊ฐ€ ๋‚œ๋‹ค. 

์™œ๋ƒํ•˜๋ฉด ?๋Š” ์–ด๋–ค ํƒ€์ž…๊ณผ๋„ ๋งค์นญ์ด ์•ˆ๋˜๊ธฐ ๋•Œ๋ฌธ์ด๋‹ค. 

 

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

๋”ฐ๋ผ์„œ ๋น„ํ•œ์ •์  ์™€์ผ๋“œ ์นด๋“œ๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ๊ฒฝ์šฐ์—๋Š” ์™€์ผ๋“œ ์นด๋“œ๋ฅผ ์‹ค์ œ ํƒ€์ž…์œผ๋กœ ๋ฐ”๊ฟ”์ฃผ๋Š” ํ—ฌํผ ๋ฉ”์„œ๋“œ๊ฐ€ ๋˜ ํ•„์š”ํ•˜๊ฒŒ ๋˜๋Š”๋ฐ... 

์•ฝ๊ฐ„ ๊ตณ์ด..? ์‹ถ๊ธด ํ•˜๋‹ค. 

 

๋ณดํ†ต ์™€์ผ๋“œ ์นด๋“œ๋Š” ํ•œ์ •์  ์™€์ผ๋“œ ์นด๋“œ๋กœ ์ฃผ๋กœ ์‚ฌ์šฉํ•˜๊ธฐ๋Š” ํ•˜๋Š”๋ฐ ๋น„ํ•œ์ •์  ์™€์ผ๋“œ ์นด๋“œ๋Š” ๋„ฃ์„ ๋•Œ๋Š” ์•„๋ฌด ํƒ€์ž…๊ณผ ๋งค์นญ๋˜์ง€ ์•Š๊ธฐ ๋•Œ๋ฌธ์— null ๋งŒ ๋„ฃ์„ ์ˆ˜ ์žˆ์ง€๋งŒ, ๊บผ๋‚ผ๋•Œ๋Š” ์ƒ๊ด€์—†๊ธฐ ๋•Œ๋ฌธ์— ๊บผ๋‚ด๊ธฐ๋งŒ ํ•œ๋‹ค๋ฉด ๋น„ํ•œ์ •์  ์™€์ผ๋“œ ์นด๋“œ๋งŒ ์‚ฌ์šฉํ•ด๋„ ๋˜๊ธด ํ•œ๋‹ค. 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

728x90