목록이펙티브자바 (88)
도당탕탕
@Override를 사용하지 않았을 때, 발생할 수 있는 문제 상황 package item40; import java.util.HashSet; import java.util.Set; public class Bigram { private final char first; private final char second; public Bigram(char first, char second) { this.first = first; this.second = second; } public boolean equals(Bigram b) { return b.first == first && b.second == second; } public int hashCode() { return 31 * first + second; }..
전통적으로 도구나 프레임워크가 특별히 다뤄야 할 프로그램 요소에는 딱 구분되는 명명 패턴을 적용해 왔다. 예컨대 테스트 프레임워크인 JUnit은 버전 3까지 테스트 메서드 이름을 test로 시작하게끔 했다. 하지만 이 방법은 다음과 같이 단점이 많다. 오타가 나면 안 된다. ( 실수로 tset~~ 하면 Junit3에서는 해당 테스트 클래스를 무시하게 된다. ) 명명 패턴은 올바른 프로그램 요소에서만 사용되리라 보증할 방법이 없다. ( 메서드가 아닌 클래스로 Test~~ 이라 지었을 때, Junit에 던지면 수행하지 않는다. ) 프로그램 요소를 매개변수로 전달할 마땅한 방법이 없다. ( 특정 예외를 던져야만 성공하는 테스트를 해야 할 경우 방법이 없다. ) 어노테이션 위 문제들은 JUnit4의 어노테이션을..
개요 Enum을 확장하고 싶을 때, enum을 상속하면 된다고 생각할 수 있는데 문제가 있다. 왜냐하면 상속된 enum type은 부모 enum type이라고 볼 수 있지만, 부모 enum type은 자식 enum type이라고 볼 수 없기 때문에, 서로 확장 관계로 보기에는 헷갈리기 때문이다. 인터페이스를 사용해서 확장성있는 Enum 구현하기 public interface Operation { double apply(double x, double y); } // BasicOperation.java public enum BasicOperation implements Operation { PLUS("+"){ @Override public double apply(double x, double y) { ret..
배열이나 리스트에서 원소를 꺼낼 때 ordinal 메서드로 인덱스를 얻는 코드가 있다. 다음 예를 보자 Plant 코드 class Plant { enum LifeCycle { ANNUAL, PERENNIAL, BIENNIAL // 한해살이, 여러해살이, 두해살이 } final String name; final LifeCycle lifeCycle; public Plant(String name, LifeCycle lifeCycle) { this.name = name; this.lifeCycle = lifeCycle; } @Override public String toString() { return name; } } 이 코드는 정원에 심는 식물들을 배열 하나로 관리하고, 이들의 생명주기를 나타내주고 있다. (..
다음은 비트 필드는 enum 타입에 집합연산을 사용할 때 주로 사용한다. public class Text{ public static final int STYLE_BOLD = 1
모든 열거 타입은 해당 상수가 몇 번째 위치인지를 반환하는 ordinal() 이라는 메서드를 제공한다. java.lang.Enum 추상 클래스의 ordinal 정수형 필드 ordinal 메서드 출처: https://javabom.tistory.com/49 하지만 이 메서드는 여러 문제점을 야기한다. 다음 예를 보자. ordinal 메서드를 잘못 사용한 예 public enum Ensemble { SOLO, DUET, TRIO, QUARTET, QUINTET, SEXTET, SEPTET, OCTET, NONET, DECET; public int numberOfMusicians() { return ordinal() + 1; } } 이 코드를 보면 동작은 하지만 유지보수하기가 끔찍한 코드다. 이유는 다음과 같..
int enum 패턴 public static final int APPLE_FUJI = 0; public static final int APPLE_PIPPIN = 1; public static final int ORANGE_NAVEL = 0; // ... 위와 같이 정의할 경우, APPLE_FUJI == ORANGE_NAVEL 과 같은 연산에 컴파일 에러가 발생하지 않아서 타입 안전하지 않다. 그리고 함수에 특정 enum 타입을 강요할 수 없다. 두 번째 문제점은 int enum 상수를 출력 문자열로 변환하는 것이 쉽지 않다는 것이다. 왜냐하면 값을 출력하면 숫자만 나오기 때문이다. enum 타입 public enum Apple {FUJI, PIPPIN, GRANNY_SMITH } public enum ..
제네릭은 Set, Map등의 컬렉션과 ThreadLocal, AtomicReference 등의 단일 원소 컨테이너에도 흔히 쓰인다. 이렇게 매개변수화되는 대상은 컨테이너 자신이기 때문에 하나의 컨테이너에서 매개변수화 할 수 있는 타입의 수가 제한된다. 예를 들어 Set에서 원소의 타입을 뜻하는 단 하나의 타입 매개변수만 있으면 되고, Map에서는 key와 value의 타입 2개만 필요하다는 식으로 보면 된다. 하지만 종종 프로그램을 구현하다 보면 좀 더 유연한 수단이 필요할 때도 있다. 이는 쉽게 해결할 수 있는데 바로 타입 안전 이종 컨테이너 패턴으로 해결하면 된다. 타입 안전 이종 컨테이너 패턴 이 패턴은 다음과 같다. 컨테이너 대신 키를 매개변수 화한 다음, 컨테이너에 값을 넣거나 뺄 때 매개변수화..