Effective Java 3E

    학습기록 - 비트 필드 대신 EnumSet을 사용하라

    열거한 값들이 주로 (단독이 아닌) 집합으로 사용될 경우, 예전에는 각 상수에 서로 다른 2의 거듭제곱 값을 할당한 정수 열거 패턴을 사용해 왔다. 1 2 3 4 5 6 7 8 public class Text{ public static final int STYLE_BOLD = 1

    학습기록 - ordinal 메서드 대신 인스턴스 필드를 사용하라

    대부분의 열거 타입 상수는 자연스럽게 하나의 정숫값에 대응된다. 그리고 모든 열거 타입은 해당 상수가 그 열거 타입에서 몇 번째 위치인지를 반환하는 ordinal 이라는 메서드를 제공한다. 이런 이유로 열거 타입 상수와 연결된 정숫값이 필요하면 ordinal 메서드를 이용하고 싶은 유혹에 빠진다. 다음 코드는 합주단의 종류를 연주자가 1명인 솔로부터 10명인 디텍트까지 정의한 열거타입이다. 1 2 3 4 5 6 public enum Ensemble{ SOLO, DUET, TRIO, QUARTET, QUINTET, SEXTET, SEPTET, OCTET, NONET, DECTET; public int numberOfMusicians(){return ordinal() +1;} } Colored by Colo..

    학습기록 - int 상수 대신 열거 타입을 사용하라

    열거 타입은 일정 개수의 상수 값을 정의한 다음, 그 외의 값은 허용하지 않는 타입이다. 사계절, 태양계의 행성, 카드게임의 카드 종류 등이 좋은 예다. 자바에서 열거 타입을 지원하기 전에는 다음 코드처럼 정수 상수를 한 묶음 선언해서 사용하곤 했다. 1 2 3 4 5 6 7 private static final int APPLE_FUJI = 0; private static final int APPLE_PIPPIN = 1; private static final int APPLE_GRANNY_SMITH = 2; private static final int ORANGE_NAVEL = 0; private static final int ORANGE_TEMPLE = 1; private static final in..

    학습기록 - 타입 안전 이종 컨테이너를 고려하라

    제네릭은 Set, Map 등의 컬렉션과 ThreadLocal, AtomicReference 등의 단일원소 컨테이너에도 흔히 쓰인다. 이런 모든 쓰임에서 매개변수화 되는 대상은 (원소가 아닌) 컨테이너 자신이다. 따라서 하나의 컨테이너에서 매개변수화할 수 있는 타입의 수가 제한된다. 컨테이너의 일반적인 용도에 맞게 설계된 것이니 문제 될 건 없다. 예컨대 Set에는 원소의 타입을 뜻하는 단 하나의 타입 매개변수만 있으면 되며, Map에는 키와 값의 타입을 뜻하는 2개만 필요한 식이다. 하지만 더 유연한 수단이 필요할 때도 종종 있다. 예컨대 데이터베이스의 행(row)은 임의 개수의 열(column)을 가질 수 있는데, 모두 열을 타입 안전하게 이용할 수 있다면 멋질 것이다. 다행히 쉬운 해법이 있다. 컨테..

    학습기록 - 제네릭과 가변인수를 함께 쓸 때는 신중하라

    가변인수(varargs) 메서드와 제네릭은 자바 5 때 함께 추가되었으니 서로 잘 어우러지리라 기대하겠지만, 슬프게도 그렇지 않다. 가변인수는 메서드에 넘기는 인수의 개수를 클라이언트가 조절할 수 있게 해주는데, 구현 방식에 허점이 있다. 가변인수 메서드를 호출하면 가변인수를 담기 위한 배열이 자동으로 하나 만들어진다. 그런데 내부로 감춰야 했을 이 배열을 그만 클라이언트에 노출하는 문제가 생겼다. 그 결과 varargs 매개변수에 제네릭이나 매개변수화 타입이 포함되면 알기 어려운 컴파일 경고가 발생한다. 실체화 불가 타입은 런타임에는 컴파일타임보다 타입 관련 정보를 적게 담고 있음을 배웠다. 그리고 거의 모든 제네릭과 매개변수화 타입은 실체화 되지 않는다. 메서드를 선언할 때 실체화 불가 타입으로 va..

    학습기록 - 한정적 와일드카드를 사용해 API 유연성을 높이라

    이전에도 이야기했듯 매개변수화 타입은 불공변(invariant)이다. 즉, 서로 다른 타입 Type1과 Type2가 있을 때 List은 List의 하위 타입도 상위 타입도 아니다. 직관적이지 않겠지만 List은 List의 하위 타입이 아니라는 뜻인데, 곰곰이 따져보면 사실 이쪽이 말이 된다. List에는 어떤 객체든 넣을 수 있지만 List에는 문자열만 넣을 수 있다. 즉, List은 List가 하는 일을 제대로 수행하지 못하니 하위 타입이 될 수 없다(리스코프 치환 원칙에 어긋난다). 하지만 때론 불공변 방식보다 유연한 무언가가 필요하다. Stack 클래스를 떠올려보자. 여기 Stack의 public API를 추려보았다. 1 2 3 4 5 6 public class Stack{ public Stack(..