이펙티브 자바 아이템 31 - 한정적 와일드카드를 사용해 API 유연성을 높이라 - 완벽 공략
아이템 31 - 한정적 와일드카드를 사용해 API 유연성을 높이라 - 완벽 공략
이 글은 백기선 님의 이펙티브 자바 강의와 이펙티브 자바 3 / E 편을 참고하여 작성하였습니다.
타입 추론
타입 추론은 타입을 추론하는 컴파일러의 기능이다.
자바에서는 타입 추론을 여러가지 형태로 지원하고 버전이 올라가면서 지원하는 범위와 용도가 늘고 있다.
public class BoxExample {
private static <U> void addBox(U u, List<Box<U>> boxes) {
Box<U> box = new Box<>();
box.set(u);
boxes.add(box);
}
private static <U> void outputBoxes(List<Box<U>> boxes) {
int counter = 0;
for (Box<U> box: boxes) {
U boxContents = box.get();
System.out.println("Box #" + counter + " contains [" +
boxContents.toString() + "]");
counter++;
}
}
private static void processStringList(List<String> stringList) {
}
public static void main(String[] args) {
ArrayList<Box<Integer>> listOfIntegerBoxes = new ArrayList<>();
BoxExample.addBox(10, listOfIntegerBoxes);
BoxExample.addBox(20, listOfIntegerBoxes);
BoxExample.addBox(30, listOfIntegerBoxes);
BoxExample.outputBoxes(listOfIntegerBoxes);
// Target Type
List<String> stringlist = Collections.emptyList();
List<Integer> integerlist = Collections.emptyList();
BoxExample.processStringList(Collections.emptyList());
}
}
타입 추론은 자바 컴파일러가 어떤 타입을 쓸지 우리가 명시하지 않아도 알아내는 것이다.
위의 코드에서 ArrayList<Box<Integer>> listOfIntegerBoxes = new ArrayList<>();
부분을 보자.
타입 추론이 없었다면 ArrayList<Box<Integer>> listOfIntegerBoxes = new ArrayList<<Box<Integer>>();
이렇게 정의했어야했다.
그러나 타입 추론이 있기 때문에 <>
연산자를 사용해 타입 선언을 생략할 수 있다.
컴파일러가 왼쪽에 정의되어있는 타입을 보고 타입을 추론해준다.
주의할 점은 new ArrayList()
이렇게 정의하면 로 타입 을 사용하게 된다는 것이다.
그러므로 반드시 <>
연산자를 사용해야한다.
이러한 타입 추론은 제네릭 메서드 호출 시에도 동일하게 적용된다.
addBox
를 호출 할 때 리턴타입을 BoxExample<Integer>.addBox(10, listOfIntegerBoxes);
처럼 적어주어야 하지만
타입 추론 덕분에 BoxExample.addBox(10, listOfIntegerBoxes);
로 선언할 수 있다.
List<String> stringlist = Collections.emptyList();
에서
List<String> stringlist
는 타겟 타입 이다.
이 타겟 타입 을 보고 Collections.emptyList()
애서 우리가 원하는 타입으로 만들어준다.
// emptyList 내부
public static final <T> List<T> emptyList() {
return (List<T>) EMPTY_LIST;
}
타겟 타입을 보고 T
라는 타입을 추론하게 된다.
타겟 타입의 범위는 자바 8 에서 메서드의 인자 타입까지 확장이 된다.
private static void processStringList(List<String> stringList) {
}
processStringList
메서드에서 인자로 받고 있는게 List<String>
타입이기 때문에
자바 7버전 에서는 BoxExample.processStringList(Collections.<String>emptyList());
처럼 타입을 명시했다.
자바 8버전 부터는 BoxExample.processStringList(Collections.emptyList());
로 코드를 작성해도 타겟 타입을 보고 타입을 추론하게 된다.
var listOfIntegerBoxes = new ArrayList<Box<Integer>>();
최근에는 위와 같이 변수의 타입 추론도 가능해졌다.