티스토리 뷰
프로그래밍 세계에는 매직 넘버를 피하라는 격언이 있다
위 격언을 지키기 위해 Config 같은 설정 클래스에서 초기화 과정에 값을 넣어주는 경우를 제외하고,
재사용 가능성이 있는 상수라면 흔히들 아래와 같이 작성하기도 한다
public static final int APPLE_FUJI = 0;
public static final int APPLE_PIPPIN = 1;
public static final int ORANGE_FUJI = 0;
public static final int ORANGE_PIPPIN = 0;
위처럼 표현할 시, 반복되는 prefix가 존재하고 더 심각한 문제는 타입 안전성이 보장되지 않는 것이다
위의 예시는 두 단어로 이어졌을 뿐이기에 가독성도 나쁘지 않고 그럭저럭 쓸 만 하지만
값을 여러 단어로 표현해야 하면 급격하게 가독성이 구데기가 되고 코드 정렬을 박살내기 쉽다 (한 라인에서 벗어나게 되므로)
쟤네들은 상수에 이름을 붙인 것이므로 잘못된 위치에 갖다 넣어도 컴파일 에러도 뜨지 않고
문제를 해결하려 일일이 쟤네를 다 찾아다니기도 버거워진다
요런 경우에 자바가 제공하는 특별한 참조 타입인 enum을 야무지게 사용할 수 있는데
책에 나온 예시를 간추려 보면 아래와 같이 사용할 수 있다
enum에 필드를 만들고 값을 할당하여 mass(), radius() 같이 편리하게 꺼내쓸 수도 있다
사용 예시는 Planet.EARTH.mass()와 같이 된다
public enum Planet {
MERCURY(3.302e+23, 2.439e6),
VENUS(4.4869e+24, 6.052e6),
EARTH(6.419e+23, 3.393e6);
private final double mass;
private final double radius;
Planet(double mass, double radius) {
this.mass = mass;
this.radius = radius;
}
public double mass() {
return mass;
}
public double radius() {
return radius;
}
}
여기까진 해피해피한데 상수를 enum으로 표현할 때 치명적인 단점이 있다
무려 9년 전 글이지만 아직도 해결되지 않은 문제니 살펴보도록 하자
반드시 상수 값으로 넘겨야 하는 곳에는 enum의 메서드를 사용해 넘길 수 없다는 것이다
대표적인 예로 애노테이션에 옵션을 줄 때가 해당되는데
한 번은 타입 안전성을 기가 막히게 지키기 위해 모든 Constants 클래스를 enum으로 바꾸고 사용했던 적이 있다
애노테이션 옵션 또한 매직 넘버를 줄 수 없으니 enum의 메서드를 사용해 값을 넘기려 했는데 띠용?!
혹시나 될랑가 해서 enum의 필드를 public으로 바꾸고 할당해봐도 똑같은 에러를 뿜는다
메서드는 그렇다 치고 public 필드 할당은 왜 안 되는지 궁금해서 메인 메서드 안에서 찍어봤는데
필드 자체도 expression으로 인식된다, 요건 왜 안 되는지 추후에 더 알아봐야겠다
옵션으로 주는 값이 반드시 상수여야 한다, 당연하게도 enum의 메서드로는 넘길 수 없다
따라서 그 대안으로 해결할 방법이 두 가지 (번외로 한 가지 더) 있는데
1. 초기 예시 코드처럼 Constants 클래스를 이용해 문자열 상수를 만들어 둔다
2. enum 안에 문자열 상수를 만들어 둔다
어느 쪽이든 찜찜함을 안고 가야 한다
두 방식 다 문자열 상수를 이용하는 것이고 위치를 어디에 두냐만 다르다
특히 객체지향 자바 개발자라면 클래스의 책임을 생각하지 않을 수 없으니
enum 안의 문자열 상수 위치가 옳은 것인지 끊임없이 고민할 수밖에 없게 된다
개발자가 직접 작성해야 할 prefix를 줄여준다는 점을 고려하면 enum에 두는 게 나쁘지 않아 보인다
다만 실무에서 사용할 때는 원칙 보다 실리니 enum에 다 흩뿌려 놓는 것보다 모아 두는 것을 선호하는 것 같다
이런 문제점을 파악했으니 enum으로 할지 Constants로 할지 선택 기준은 간단하다
애노테이션 옵션에 할당해야 하는가? Constants로 하자
애노테이션 옵션에 할당하지 않는가? enum으로 하자
번외로 자신이 만든 커스텀 애노테이션에 적용할 예정이라면 가능한 enum으로 받아버리고
아래와 같이 annotation processing 과정을 직접 작성해주도록 하자
'Java > Effective Java' 카테고리의 다른 글
[Item36] 비트 필드와 EnumSet (0) | 2022.03.19 |
---|---|
[Item35] ordinal 금지 (0) | 2022.03.15 |
[Item33] Super Type Tokens (0) | 2022.03.13 |
[Item32] varargs는 신중히 (0) | 2022.03.11 |
[Item31] 한정적 와일드카드 뭐시기?? (0) | 2022.03.10 |