2023. 3. 22. 14:03ใJAVA/Effective JAVA
[์ดํํฐ๋ธ ์๋ฐ] 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 ๋ง ๋ฃ์ ์ ์์ง๋ง, ๊บผ๋ผ๋๋ ์๊ด์๊ธฐ ๋๋ฌธ์ ๊บผ๋ด๊ธฐ๋ง ํ๋ค๋ฉด ๋นํ์ ์ ์์ผ๋ ์นด๋๋ง ์ฌ์ฉํด๋ ๋๊ธด ํ๋ค.