용어 | 예 |
형인자 자료형(parameterized type) | List<String> |
실 형인자(actual type parameter) | String |
제네릭 자료형(generic type) | List<E> |
형식 형인자(formal type parameter) | E |
비한정적 와일드카드 자료형(unbounded wildcard type) | List<?> |
무인자 자료형(raw type) | List |
한정적 형인자(bounded type parameter) | <E extends number> |
재귀적 형 한정(recursive type bound) | <T extends Comparable<T>> |
한정적 와일드카드 자료형(bounded wildcard type) | List<? Extends Number> |
제네릭 메서드(generic method) | Static <E> List<E> asList(E[] a) |
자료형 토큰(type token) | String.class |
규칙23: 새 코드에는 무인자 제네릭 자료형을 사용하지 마라.
무인자 자료형: 예를 들어 List<E>의 무인자 자료형은 List이다.
무인자 자료형을 쓰면 형 안전성이 사라지고 제네릭의 장점 중 하나인 표현력 측면에서 손해를 보게 된다.
무인자 자료형을 사용하면 런타임 도중 예외가 발생할 수 있으므로 새로 만드는 코드에는 무인자 자료형을 사용하지 말아야 한다.
규칙24: Unchecked warning을 제거하라.
Generic 사용시 많은 unchecked warning을 마주하기 쉽다.
가능한 한 모두 제거하되 제거할 수 없는 메시지는 형 안전성이 확실할 때만 @SuppressWarnings annotation을 사용해라. 또한 가능한 한 작은 범위에 적용해라. 그리고 사용할 때마다 왜 형 안전성을 위반하지 않는지 밝힌느 주석을 반드시 밝혀라.
규칙25: 배열 대신 리스트를 써라.
배열은 공변 자료형(covariant)이다. 이는 sub가 super의 하위 자료형이라면 sub[]도 super[]의 하위 자료형이라는 것이다. 반면 제네릭은 불변 자료형(invariant)이다. Type1과 Type2가 있을 때 List<Type1>은 List<Type2>의 상위 자료형이나 하위 자료형이 될 수 없다.
배열의 각 원소 자료형은 runtime에 결정된다. 반면 제네릭은 compile 시점에만 적용되고 그 정보는 프로그램 실행 시 삭제된다.
서로 규칙이 다르기 때문에 쉽게 혼용할 수 없다.
규칙26: 가능하면 제네릭 자료형으로 만들 것
제네릭 자료형은 클라이언트가 형변환을 해야만 사용할 수 있는 자료형보다 안전할 뿐만 아니라 사용하기도 쉽다. 기존 클라이언트 코드를 깨지 않고도 새로운 사용자에게 더 좋은 API를 제공할 수 있게 될 것이다.
규칙27: 가능하면 제네릭 메서드로 만들 것
클래스뿐만 아니라 메서드도 제네릭의 혜택을 볼 수 있다. 여러 binarySearch, sort와 같은 것은 제네릭으로 구현되어 있다.
형인자를 선언하는 형인자 목록은 메서드 수정자의 반환값 자료형 사이에 둔다.
// generic static factory method
public static <K, V> HashMap<K, V> newHashMap(){
return new HashMap<K, V>();
}
// generic singleton factory pattern
Private static UnaryFunction<Object> IDENTITY_FUNCTION =
New UnaryFunction<Object>(){
Public Object apply(Object arg) {return arg;}
};
제네릭 자료형처럼 제네릭 메소드는 클라이언트가 직접 입력 값과 반환값의 자료형을 형변환해야하는 메서드보다 사용하기 쉽고 형 안전성도 높다.
규칙28: 한정적 와일드카드를 써서 API 유연성을 높여라.
유연성을 최대화하려면 객체의 producer나 consumer 구실을 하는 메소드 인자의 자료형은 와일드카드 자료형으로 하는 것이 좋다. 어떤 와일드카드를 쓸지 어렵다면 아래 약어를 활용하자.
PECS -> (Produce – Extends, Consumer – Super)
다시 말해서 인자가 T 생산자라면 <? Extends T>라고 하고 T 소비자라면 <? Super T>라고 해라.
단 반환값에는 와일드카드 자료형을 사용해서는 안 된다. 클래스 사용자가 와일드카드 자료형에 대해 고민하게 된다면 그것은 아마도 클래스 API가 잘못 설계된 탓일 것이다.
규칙29: 형 안전 다형성 컨테이너를 쓰면 어떨지 따져보라.
보통 container 별로 형인자 수는 고정된다. 예를 들어 Set은 하나, Map은 key와 value 하나씩 필요할 것이다. 하지만 좀 더 유연한 방법이 필요할 수 있다. 예를 들어 DB에 저장되는 레코드의 경우 임의의 개수의 column을 가진다. 이 때 typesafe을 깨지 않으면서 각 열에 접근할 방법이 있다면 좋을 것이다.
-> Container 대신 key에 형인자를 지정하고 container에 값을 넣거나 뺄 때마다 key를 제공한다.
'DevBook' 카테고리의 다른 글
Effective Java 2판 - 7장 정리 (Method) (0) | 2024.05.18 |
---|---|
Effective Java 2판 - 6장 정리 (Annotation) (2) | 2024.05.14 |
Effective Java 2판 - 4장 정리 (Class, Interface) (0) | 2024.05.14 |
Effective Java 2판 - 2, 3장 정리 (객체 생성, 공통 메서드) (0) | 2024.04.29 |
오브젝트 1장 - 객체, 설계 (0) | 2024.01.05 |