Enum과 Annotation의 Effective한 사용

박근수·2024년 11월 27일
0

01. int 상수 대신 enum을 사용하라

구별을 위해서는 enum을 사용하자

//간단한 형태의 enum
@AllArgsConstructor
@Getter
public enum Fruit{
	APPLE(1000, 20, "RED"),
    PEACH(2000, 9, "YELLO");
    
    private final int price;
    private final int box;
    private final String color;
    
    public int boxPrice(){
    	return price * box;
    }
}

fromString method

private static final Map<STring, Fruit> stringToEnum = Stream.of(values())
.collect(Collectors.toMap(Objects::toString, e->e));
public static Optional<Fruit> fromString(String symbol){
	return Optional.ofNullable(StringToEnum.get(Symbol));
}
//타 서버에서 불확실성을 가지고 enum이 넘어오거나 DB등의 값을 처리할 때 등등 유용할 수 있다.

02. ordinal method 대신 instant field를 사용하라

Enum의 Ordinal vs instant Filed

//ordinal() 사용
public enum Ensemble{
	SOLO, DUEL, TRIO, QUARTET;
    
    public int numberOfMusicians(){
    	return ordinal() + 1;
    }
}

//instatnt Filed 사용
@AllArgsConstructor
public enum Ensemble{
	SOLO(1),DUEL(2),TRIO(3),
    QUARTET(4),TRIPLE_QUARTET(12);
    
    private final int numberOfMusicians;
    
    public int numberOfMusicians(){
    	return ordinal() + 1;
    }
}

Enum에서 ordinal()이라는 enum의 번호를 변환해 주는 메서드가 있다.
하지만 경우에 따라 넘버링을 bit로 하는 경우도 있고 코드를 잘못 건드리면 겉잡기 힘들다.
그러니 인스턴트 필드에 값을 저장해서 사용하는 것이 좋다.

03. bit field 대신 Enumset을 사용하라

Bit field로 구현한 style code를 가져오는 Util class

public class TextStyleUtil{
	public static final int STYLE_BOLD = 1 << 0; //1
	public static final int STYLE_ITALIC = 1 << 1; //2
	public static final int STYLE_UNDERLINE = 1 << 2 //4
	public static final int STYLE_STRIKETHROUGH = 1 <> 3 // 8
}

Enumset으로 구현한 style code 가져오기

@Getter
@AllArgsConstructor
public enum TestStyle{
	BOLD(1), ITALIC(2), UNDERLINE(4), STRIKETHROUGH(8);
    
    private final int code;
    
    public static int getStyleCode(Set<TestStyle) styles){
		return style.stream().mapToInt(TestStyle::getCode).sum();    
	}
}

...
int styleCode = TextStyle.getStyleCode(Enumset.of(TextStyle.BOLD,TextStyle.ITALIC));

04. ordinal indexing 대신 EnumMap을 사용

ordinal()을 사용한 좋지 못한 코드

요구사항 : 식묵들을 배열 하나로 관리, 생애주기로 묶는다.

Set<Plant>[] plantsByLifeCycle = 
(Set<Plant>[]) new Set[Plant.LifeCycle.values().legth];

for(int i = 0; i<plantByLifeCycle.length;i++){
	plantByLifeCycle[i] = new HashSet<>();    
}
for(Plant p : garden){
	plantsByLifeCycle[p.lifecycle.ordinal()].add(p);
}

배열 대신 EnumMap 변경

Map<Plant.LifeCycle, Set<Plant> plantsByLifeCycle =
new EnumMap<>(Plant.LifeCycle.clas);
for(Plane.LifeCycle lc : Plant.LifeCycle.values()){
	plantsByLifeCycle.put(lc, new HashSet<>());
}

for(Plant p : graden){
	plantsByLifeCycle.get((plantsByLifeCycle)).add(p);
}

...
//EnumMap의 Put 내부
public V put(K ket, V value){
	typeCheck(key);
    
    int index = ket.ordinal();
    Object oldValue = vals[index];
    vals[index] = maskNull(value);
    if(oldValue == null) size ++;
    
    return unmaskNull(oldValue);
}

05. 명명 패턴보다 Annotation을 사용하라

명명패턴

jpa의 custom method의 경우 또한 postfix가 impl로 고정 되어 있다.

The most important part of the class name that 
corresponds to the fragment interface is the Impl postifx.

명명 패턴의 문제

* 오타에 취약
* 올바른 프로그램 요소에마서만 사용되라는 법이 없음
* 프로그램 요소를 매개 변수로 전달할 방법이 없다

Annotation

예제

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface Test{
}

annotation 의 속성

public enum RetentionPolicy{
	SOURCE, // 컴파일러에 의해 무시
    CLASS, // 런타임 시 무시 (컴파일 시에만 체크)
    RUNTIME // 런타임 시에도 확인
}

public enum ElementType{
	Type,
    FIELD,
    METHOD,
    PARAMETER,
    CONSTRUCTOR.
    LOCAL_VARIABLE,
    ...
    ...
    MODULE
}
profile
개발블로그

0개의 댓글