[이펙티브자바] 5장 제네릭(item26-33) 정리

예니·2022년 9월 18일
0

이펙티브자바

목록 보기
4/11

아이템 26. 로 타입은 사용하지 말라

  • 로타입은 뭐든지 다 들어간다. → 꺼낼 때, 값을 항상 올바른 타입으로 캐스팅해줘야 한다. → 타입안정성, 표현력을 잃게 된다.
  • 비한정적 와일드카드 타입(ex. List<?>)은 어떤 타입이든 상관없이 받을 수 있어 타입안정성을 보장해준다.
    얘는 null외에 아무것도 못 넣어서 불변식도 보장한다.
  • List<Object>List<String>은 공변관계 아니다. 그냥 다른 타입이라고 생각하자
  • 런타임에는 제네릭 타입 정보가 지워진다!
  • 로타입을 써도 좋은 곳
    1. 클래스 리터럴
    2. instanceof (로타입 or 비한정적 와일드카드 타입)

아이템 27. 비검사 경고를 제거하라

  • 가능한 모든 unchecked warning을 제거하라
    모두 제거하면 타입 안정성 보장
  • @SuppressWarnings는 가능한 한 좁은 범위에 적용하자
    경고를 무시해도 안전한 이유를 주석으로 남겨라

아이템 28. 배열보다는 리스트를 사용하라

  • 배열은 공변이고, 제네릭은 불공변이다
    공변이란?
    Sub이 Super의 하위 타입이라면 Sub[]Super[]의 하위 타입이 된다 (같이 변한다)
    제네릭은 불공변이라 List<Sub>, List<Super>는 아예 남남이다.
  • 배열은 실체화(reify)된다
    배열은 런타임에도 담기로한 타입을 알지만, 제네릭은 타입 정보가 런타임에는 소거된다.
  • 제네릭은 컴파일 에러를 던져주니까 런타임에는 타입안전하다.

아이템 29. 이왕이면 제네릭 타입으로 만들라

  • 클라이언트가 사용할 때 매번 형변환을 해야하고, 그 과정에서 런타임 에러가 나는 것을 방지하기 위해 이왕이면 제네릭 타입으로 만들자.
  • 배열을 사용하는 코드를 제네릭으로 만드는 두가지 방법이 나옴
  • 방법 1. Object 배열을 제네릭 배열로 형변환
E[] elements = (E[]) mew Object[10];
  • 방법 2. 꺼낼 때마다 E로 형변환해주기
  • 방법 1이 간단하지만, 힙 오염을 일으킬 수 있음
    컴파일타임 타입 =! 런타임 타입

아이템 30. 이왕이면 제네릭 메서드로 만들라

  • 타입 매개변수들을 선언하는 타입 매개변수 목록은 메서드의 제한자와 반환 타입 사이에 온다.
  • 재귀적 타입 한정(Recursive type bound)
    자기 자신이 들어간 표현식을 사용하여 타입 매개변수의 허용 범위를 한정할 수 있다.
	public static <E extends Comparable<E>> E max(Collection<E> c) {...}
  • 제네릭 타입과 마찬가지로, 매개변수와 반환값을 형변환 해야한다면 제네릭 메서드가 더 안전하고 쉽다.

아이템 31. 한정적 와일드카드를 사용해 API 유연성을 높이라

  • 유연성을 높이기 위해 원소의 생산자나 소비자용 입력 매개변수에 와일드카드 타입을 사용하라.
  • PECS : produce-extends, consumer-super 를 꼭 기억하자
  • 반환 타입에는 한정적 와일드카드 타입을 사용하면 안돼!
    Comparable, Comparator는 모두 소비자다.
    클래스 사용자가 와일드카드 타입 신경쓰게되면 뭔가 잘못된 것임
  • 비한정적 타입 매개변수(List<E>) vs 비한정적 와일드카드(List<?>)
    메서드 선언에 타입 매개변수가 한 번만 나오면 와일드카드로 대체하라
    근데 List<?>에는 null만 넣을 수 있음; private 도우미 메서드를 사용해야한다.

아이템 32. 제네릭과 가변인수를 함께 쓸 때는 신중하라

  • 가변인수 메서드를 호출하면 가변인수를 담기 위해 배열이 생성되기 때문에, 실체화 불가 타입인 제네릭, 매개변수화 타입이 포함되면 안전하지 않다.
  • 제네릭 배열을 직접 만드는 것은 허용하지 않음. 제네릭 varargs 매개변수를 받는 메서드는 선언할 수 있음 → 개발 편의성을 위해!
  • @SafeVaragrs - 메서드 작성자가 해당 메서드가 타입 안전함을 보장하는 장치
  • @SafeVaragrs는 메서드가 안전할 때만 쓰자
    제네릭 varargs 매개변수 배열에 다른 메서드가 접근하도록 허용하면 안전하지 않다.
    재정의할 수 없는 메서드에만 달아야 한다. (그래서 정적 메서드, final 인스턴스 메서드, private 인스턴스 메서드에만 허용)

아이템 33. 타입 안전 이종 컨테이너를 고려하라

  • ThreadLocal<T>, AtomicReference<T> 같은 것은 단일원소 컨테이너임. 매개변수화되는 대상이 원소가 아닌 자기 자신이다.
  • 더 유연한 타입 안전 이종 컨테이너!
    컨테이너 대신 키를 매개변수화, 컨테이너에 값을 넣,뺄 때 매개변수화한 키를 같이 제공하면 된다.
    → 제네릭 시스템이 '값 타입 == 키 타입'을 보장해준다.
  • 타입 토큰
    컴파일, 런타임 타입 정보를 알기 위해 메서드들이 주고 받는 class 리터럴 (ex. String.class, Integer.class ..)
    List<String>.class 처럼 실체화 불가 타입에는 못 쓴다.
  • 슈퍼 타입 토큰
    List<String>.class 처럼 실체화 불가 타입도 클래스 리터럴 사용할 수 있게 해주는 묘수
    ex. jackson의 TypeReference

0개의 댓글