전체 글 194

[Effective Java] item 37. ordinal 인덱싱 대신 EnumMap을 사용하라

[Effective Java] item 37. ordinal 인덱싱 대신 EnumMap을 사용하라 핵심 정리 배열의 인덱스를 얻기 위해 ordinal을 쓰는 것은 일반적으로 좋지 않으니, 대신 EnumMap을 사용하라. 다차원 관계는 EnumMap으로 표현하라. "어플리케이션 프로그래머는 Enum.ordinal을 (웬만해서는) 사용하지 말아야 한다.(아이템 35)"는 일반 원칙의 특수한 사례다. 배열이나 리스트에서 원소를 꺼낼 때 ordinal 메서드로 인덱스를 얻는 방식 정원에 심은 식물들을 배열 하나로 관리하고, 이들을 생애주기(한해살이, 여러해살이, 두해살이)별로 묶는다. 생애주기별로 총 3개의 집합을 만들고 정원을 한바퀴 돌며 각 식물을 해당 집합에 넣는다. 이 때 어떤 프로그래머는 집합들을 배열..

[Effective Java] item 36. 비트 필드 대신 Enumset을 사용하라

[Effective Java] item 36. 비트 필드 대신 Enumset을 사용하라 핵심 정리 열거할 수 있는 타입을 한대 모아 집합 형태로 사용한다고 해도 비트 필드를 사용할 이유는 없다. EnumSet 클래스가 비트 필드 수준의 명료함과 성능을 제공하고 열거타입의 장점까지 선사하기 때문이다. EnumSet의 유일한 단점이라면 불변 EnumSet을 만들 수 없다는 것이다. 그때까지는 (명확성과 성능이 조금 희생되지만) Collections.unmodifiableSet으로 EnumSet을 감싸 사용할 수 있다. 비트 필드 열거 상수 열거한 값들이 주로 (단독이 아닌) 집합으로 사용되는 경우, 예전에는 각 상수에 서로 다른 2의 거듭제곱 값을 할당한 정수 열거 패턴을 사용해왔다. 비트 필드 열거 상수 ..

[Effective Java] item 35. ordinal 메서드 대신 인스턴스 필드를 사용하라

[Effective Java] item 35. ordinal 메서드 대신 인스턴스 필드를 사용하라 대부분의 열거 타입 상수는 자연스럽게 하나의 정수값에 대응된다. 그리고 모든 열거 타입은 해당 상수가 그 열거 타입에서 몇 번째 위치인지를 반환하는 ordinal이라는 메서드를 제공한다. 이런 이유로 열거 타입 상수와 연결된 정숫값이 필요하면 ordinal 메서드를 이용하고 싶은 유혹에 빠진다. 다음 코드는 합주단의 종류를 연주자가 1명인 솔로(solo)부터 10명인 디텍트(dectet)까지 정의한 열거 타입이다. ordinal을 잘못 사용한 예 - 따라하지 말 것! public enum Ensemble { SOLO, DUET, TRIO, QUARTET, QUINTET, SEXTET, SEPTET, OCTE..

[Effective Java] item 34. int 상수 대신 열거 타입을 사용하라

[Effective Java] item 34. int 상수 대신 열거 타입을 사용하라 핵심 정리 열거 타입은 확실히 정수 상수보다 뛰어나다. 더 읽기 쉽고 안전하고 강력하다. 대다수 열거 타입이 명시적 생성자나 메서드 없이 쓰이지만, 각 상수를 특정 데이터와 연결짓거나 상수마다 다르게 동작하게 할 때는 필요하다. 드물게는 하나의 메서드가 상수별로 다르게 동작하게 할 때도 있다. 이런 열거 타입에는 switch 문 대신 상수별 메서드를 구현하자. 열거 타입 상수 일부가 같은 동작을 공유한다면 전략 열거 타입 패턴을 사용하자. 열거 타입 열거 타입: 일정 개수의 상수 값을 정의한 다음, 그 외의 값은 허용하지 않는 타입. 정수 열거 패턴 자바에서 enum을 지원하기 전에 사용하던 정수 열거 패턴public ..

[Effective Java] item 33. 타입 안전 이종 컨테이너를 고려하라

[Effective Java] item 33. 타입 안전 이종 컨테이너를 고려하라 핵심 정리 컬렉션 API로 대표되는 일반적인 제네릭 형태에서는 한 컨테이너가 다룰 수 있는 타입 매개변수의 수가 고정되어 있다. 하지만 컨테이너 자체가 아닌 키를 타입 매개변수로 바꾸면 이런 제약이 없는 타입 안전 이종 컨테이너를 만들 수 있다. 타입 안전 이종 컨테이너는 Class를 키로 쓰며, 이런 식으로 쓰이는 Class 객체를 타입 토큰이라 한다. 또한 직접 구현한 키 타입도 쓸 수 있다. 예컨대 데이터베이스의 행(컨테이너)을 표현한 DatabaseRow 타입에는 제네릭타입인 Column를 키로 사용할 수 있다. 타입 안전 이종 컨테이너 패턴(type safe heterogeneous container pattern..

[Effective Java] item 32. 제네릭과 가변인수를 함께 쓸 때는 신중해라

[Effective Java] item 32. 제네릭과 가변인수를 함께 쓸 때는 신중해라 핵심 정리 가변인수와 제네릭은 궁합이 좋지 않다. 가변인수의 기능은 배열을 노출하여 추상화가 완벽하지 못하고, 배열과 제네릭의 타입 규칙이 서로 다르기 때문이다. 제네릭 varargs 매개변수는 타입 안전하지 않지만, 허용된다. 메서드에 제네릭 (혹은 매개변수화된) varargs 매개변수를 사용하고자 한다면, 먼저 그 메서드가 타입 안전한지 확인한 다음 @SafeVarargs 애너테이션을 달아 사용하는데 불편함이 없게 하자. 가변인수 public static void display(String ...infos) { for (String info: infos) { System.out.println(s); } } 가변인..

[Effective Java] item 31. 한정적 와일드카드를 사용해 API 유연성을 높이라

[Effective Java] item 31. 한정적 와일드카드를 사용해 API 유연성을 높이라 핵심 정리 조금 복잡해지더라도 와일드카드 타입을 적용하면 API가 훨씬 유연해진다. 그러니 널리 쓰일 라이브러리를 작성한다면 반드시 와일드카드 타입을 적절히 사용해줘야 한다. PECS 공식을 기억하자. 생성자(producer)는 extends를 소비자(consumer)는 super를 사용한다. Comparable과 Comparator는 모두 소비자라는 사실도 잊지 말자. 아이템 28에서 이야기했듯 매개변수화 타입은 불공변(invariant)이다. 즉, 서로 다른 타입 Type1과 Type2가 있을 때 List은 List의 하위 타입도 상위 타입도 아니다. 직관적이지 않겠지만 List은 List의 하위 타입이 ..

[Effective Java] item 30. 이왕이면 제네릭 메서드로 만들라

[Effective Java] item 30. 이왕이면 제네릭 메서드로 만들라 핵심 정리 제네릭 타입과 마찬가지로, 클라이언트에서 입력 매개변수와 반환값을 명시적으로 형변환해야 하는 메서드보다 제네릭 메서드가 더 안전하며 사용하기도 쉽다. 타입과 마찬가지로, 메서드도 형변환 없이 사용할 수 있는 편이 좋으며, 많은 경우 그렇게 하려면 제네릭 메서드가 되어야 한다. 역시 타입과 마찬가지로, 형변환을 해줘야 하는 기존 메서드는 제네릭하게 만들자. 기존 클라이언트는 그대로 둔 채 새로운 사용자의 삶을 훨씬 편하게 만들어줄 것이다. 제네릭 메서드 클래스와 마찬가지로 메서드도 제네릭으로 만들 수 있다. 매개변수화 타입을 받는 정적 유틸리티 메서드는 보통 제네릭이다. 예컨대 Collections의 '알고리즘..

[Effective Java] item 29. 이왕이면 제네릭 타입으로 만들라

[Effective Java] item 29. 이왕이면 제네릭 타입으로 만들라 핵심 정리 클라이언트에서 직접 형변환해야 하는 타입보다 제네릭 타입이 더 안전하고 쓰기 편하다. 그러니 새로운 타입을 설계할 때는 형변환 없이도 사용할 수 있게 하라. 그렇게 하려면 제네릭 타입으로 만들어야 할 경우가 많다. 기존 타입 중 제네릭이었어야 하는 개체가 있다면 제네릭 타입으로 변경하자. 기존 클라이언트에는 아무 영향을 주지 않으면서, 새로운 사용자를 훨씬 편하게 해주는 길이다. 제네릭 타입을 왜 사용해야 하는가? JDK가 제공하는 제네릭 타입과 메서드를 사용하는 일은 일반적으로 쉬운 편이지만, 제네릭 타입을 새로 만드는 일은 조금 더 어렵다. 그래도 배워두면 그만한 값어치는 충분히 한다. 아이템 7에서 다룬 단순한..

[Effective Java] Item 28. 배열보다는 리스트를 사용하라

[Effective Java] Item 28. 배열보다는 리스트를 사용하라 핵심정리 배열과 제네릭에는 매우 다른 타입 규칙이 적용된다. 배열 공변이고 실체화 된다. 런타임에는 타입 안전하지만 컴파일 타임에는 그렇지 않다. 제네릭 불공변이고 타입 정보가 소거된다. 런타임에는 타입 안전하지 않지만 컴파일 타임에는 안전하다. 둘을 섞어 쓰다가 컴파일 오류나 경고를 만나면, 가장 먼저 배열을 리스트로 대체하는 방법을 적용해보자. 배열과 제네릭 타입에는 중요한 차이 두 가지가 있다. 배열은 공변이지만 제네릭은 불공변이다. 배열은 공변이다. Sub가 Super의 하위 타입이라면 배열 Sub[]은 배열 Super[]의 하위 타입이 된다. (공변, 즉 함께 변한다는 뜻이다.) 제네릭은 불공변이다. 서로 다른 타입 Ty..