티스토리 뷰
Item 26. raw type은 사용하지 마라
✅ 제네릭 클래스, 제네릭 인터페이스 (generic interface)
클래스와 인터페이스 선언에 타입 매개 변수가 쓰인 것. 이를 합쳐 generic type이라고 한다.
✅ raw type
제네릭 타입에서 타입 매개변수를 전혀 사용하지 않을 때를 말한다.
로 타입은 사용하지 말자. 예를 들어 List를 List로만 사용하는 것이다. 로 타입은 이전 자바 버전 호환성 땜에 사용가능하지만, 사용 안하는 게 좋다. 단 예외 2가지가 있다.
- class 리터럴
List.class는 사용할 수 없고, List.class만 가능하다. - instanceof
✅ unbounded wildcard type
?로 쓴다. 어떤 타입인지 신경쓰지 않을 때, 어떤 타입도 담을 수 있는 타입 - ✅ bounded wildcard type
'? extends 특정 클래스' 로 쓴다.
Item 28. 배열보다는 리스트를 사용하라
배열과 리스트는 타입 규칙이 달라서 섞어쓰기가 쉽지 않다.
배열은 런타임에 에러가 발생하고 제네릭(리스트)는 컴파일 타임에 에러가 발생한다. 따라서 배열을 리스트로 대체하자.
Item 29. 이왕이면 제네릭 타입으로 만들자
제네릭 타입으로 만들어서 클라이언트에서 직접 형변환하지 않아도 되어 더 안전하고 쓰기 편하게 하는 게 좋다. (타입 매개변수를 통해 타입을 명시할 수 있기 때문이다)
Item 30. 이왕이면 제네릭 메서드로 만들자
클래스와 마찬가지로 메서드도 제네릭으로 만들 수 있다.
✅ (타입 매개변수를 선언하는) 타입 매개변수 목록은 메서드의 제한자와 반환 타입 사이에 쓴다.
✅ 제네릭 싱글턴 팩터리 패턴
불변 객체를 여러 타입으로 활용할 수 있게 만들어야 할 때가 있다.
제네릭은 런타임에 타입 정보가 소거되므로 하나의 객체를 어떤 타입으로든 매개변수화할 수 있다. 하지만 이렇게 하려면 요청한 타입 매개변수에 맞게 매번 그 객체의 타입을 바꿔주는 정적 팩터리를 만들어야 한다. 이 패턴이 제네릭 싱글턴 팩터리이다.
Collections.reverseOrder, Collections.emptySet으로 사용한다.
✅ 재귀적 타입 한정
자기 자신이 들어간 표현식을 사용하여 타입 매개변수의 허용 범위를 한정할 수 있다. 주로 타입의 한정적 순서를 정하는 Comparable 인터페이스와 함께 쓰인다. <E extends Comparable<E>> ⇒ 모든 타입은 자신과 비교할 수 있다.
제네릭 타입(Item 29.)와 마찬가지로 제네릭 메서드로 클라이언트가 형변환을 하지 않도록 한다.
✅ 배열과 제네릭 차이
배열은 공변(covariant. 함께 변한다)이다. A가 B의 하위 타입이라면 A[]도 B[]의 하위가 된다. 그에 반해, 제네릭은 불공변(invariant)이다. List<A> 와 List<B> 는 서로 하위도 상위도 아니다.
- 배열은 런타임에도 타입을 확인하지만(→ 런타임 에러 발생 가능) 제네릭은 런타임 시에 타입 정보가 소거된다.
Item 31. 한정적 와일드 카드를 사용해 API 유연성을 높여라
💡 유연성을 극대화하려면 원소의 생산자나 소비자용 입력 매개변수에 와일드 카드 타입을 사용하라.
한편, 입력 매개변수가 생산자와 소비자 역할을 동시에 한다면 와일드 카드 타입을 사용하지 않는 게 좋다.
PECS 공식 : Producer - extends, Consumer - super
매개 변수화 타입 T가 생산자라면 <? extends T>
소비자라면 <? super T>
public static <E> Set<E> union (Set<E> s1, Set<E> s2)
생산자(데이터 제공) ⇒ union (Set<? extends E> s1, Set<? extends E> s2)
단, 반환 타입에는 한정적 와일드카드 타입을 사용하면 안 된다. 클라이언트도 와일드 카드 타입을 써야하기 때문
✅ parameter(매개변수)와 argument(인수)
매개변수는 메서드 선언에 정의한 변수. void add(int value)
인수는 메서드 호출 시 넘기는 실제값. add(10)
Comparable<E>보다는 Comparable<? super E>를 사용하는 편이 낫다. Comparator도 마찬가지
예를 들어 A의 클래스가 B의 하위 클래스인데 Comparable<B>만이 구현되어 있다면 <E extends Comparable<? super E>>로만 가능하다.
- 비한정적 타입 매개변수와 비한정적 와일드 카드는 유사한 점이 많다.
- 다른 점은 타입 매개변수는 메서드 안에서 해당 타입에 대한 정의나 변수를 생성할 수 있다는 것이다. 혹은 매개변수의 타입을 일치시킬 수 없다.
- ⇒ 메서드 선언에 타입 매개변수가 한 번만 나오면 와일드 카드로 대체하라 (한정적이든 비한정적이든)
Item 32. 제네릭과 가변인수를 함께 쓸 때는 신중하라
✅ 가변 인수 (varags)
메서드에 넘기는 인수의 개수를 한 개 이상으로 받을 수 있다. (Type... param) 과 같이 사용된다.
실제로는 Object[] 배열이 생긴다.
가변인수 메서드를 호출할 때 varargs 매개 변수를 담는 제네릭 배열이 만들어진다. 제네릭과 타입 매개 변수는 실체화 불가 타입이고, 이 변수가 타입이 다른 객체를 참조하면 힙 오염이 발생한다.
⇒ 제네릭 varargs 배열 매개변수에 값을 저장하는 것은 안전하지 않다.
- 타입 안전성
- 메서드 내에서 배열(가변인수 매개변수를 담는 제네릭 배열)에 아무것도 저장하지 않고 그 배열의 참조가 밖으로 노출되지 않는다면 안전!
- 매개 변수 배열이 호출자로부터 그 메서드로 순수하게 인수들을 전달하는 일만 한다면 안전!⇒ 제네릭 varargs 매개변수 배열에 다른 메서드가 접근하도록 허용하면 안전하지 않다.
💡 정리하자면
- varargs 매개 변수 배열에 아무것도 저장하지 않는다.
- 그 배열(혹은 복제본)을 신뢰할 수 없는 코드에 노출하지 않는다.
Item 33. 타입 안전 이종 컨테이너를 고려하라
✅ 컨테이너
객체를 저장하는 것 중 배열이 있는데, 한 번 크기가 정해지면 변경될 수 없다. 따라서 java.util 라이브러리에 container class들이 제공된다. List, Map, Set, Queue, ThreadLocal 등이 있다.
✅ Class
Class 클래스는 제네릭이다. String.class는 사실 Class 이다.
✅ printf("%n");
여기서 %n 은 플랫폼에 맞는 줄바꿈 문자로 자동 대체된다
✅ 타입 안전 이종 컨테이너 패턴 (type safe heterogeneous container)
Set<E>, Map<K, V> 와 같은 제네릭은 컨테이너 자신을 매개변수화한다. 따라서 하나의 컨테이너에서 매개변수화할 수 있는 타입의 수가 제한된다. 이렇게 컨테이너 대신에 키를 매개변수화하여 더 유연하게 사용 가능한 패턴이 타입 안전 이종 컨테이너 패턴이다.
키를 매개변수화한 다음, 컨테이너에 값을 넣거나 뺄 때 매개변수화한 키를 함께 제공하면 된다. 이렇게 하면 제네릭 타입 시스템이 값의 타입이 키와 같음을 보장해준다. 키로 쓰이는 Class 객체를 타입 토큰이라 한다.
Map<Class<?>, Object> map
String.class, Integer.class 등이 Key가 된다
EnumMap에도 사용되는 개념이다
✅ Class 클래스의 cast 메서드
- cast 메서드는 형 변환 연산자의 동적 버전이다.
- 주어진 인수가 해당 타입의 인스턴스라면 그대로 변환하고, 아니면 ClassCastException을 발생시킨다
- 이 간단한 로직을 굳이 사용하는 이유는?
Class 클래스가 제네릭이라는 이점을 완벽히 활용하기 때문! → 타입 안전
public class Class{ T cast(Object obj); }
✅ Collections의 컬렉션 래퍼들
checkedSet, checkedList, checkedMAp 메서드들은 모두 제네릭으로, Class 객체와 컬렉션의 컴파일타임 타입이 같음을 보장한다
'Java' 카테고리의 다른 글
Java API 비동기 호출 (0) | 2021.12.22 |
---|---|
lombok.Builder 로 빌더 패턴 사용한 클래스의 필드를 초기화하고 싶다면 (0) | 2021.12.22 |
Generic (0) | 2020.10.22 |
static method 는 언제 써야할까 (0) | 2020.09.29 |
Refactoring 참고 링크 모음 (0) | 2020.09.09 |
- Total
- Today
- Yesterday
- WebClient
- point
- Lombok
- effective-java
- 코테 log
- Java
- Generic
- 사고..
- 이벤트스토밍
- 암호화
- Spring-Boot
- ActiveAdmin
- ruby
- TroubleShooting
- IntelliJ
- 이펙티브자바
- DesignSystem
- querydsl
- gitignore
- annotation
- SQL 전문가 가이드
- Encoding
- aws
- Git
- fetchResults
- 메모리 릭
- ASCII
- sort algorithm
- 실용주의
- SHA
일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | 3 | ||||
4 | 5 | 6 | 7 | 8 | 9 | 10 |
11 | 12 | 13 | 14 | 15 | 16 | 17 |
18 | 19 | 20 | 21 | 22 | 23 | 24 |
25 | 26 | 27 | 28 | 29 | 30 | 31 |