본문 바로가기
JAVA

enum 이 자식!!

by Big Sun 2023. 3. 1.
728x90

enum이 뭘까??

 

enum이란 Enumeration의 앞 글자로 열거라는 의미를 갖습니다. 

자바에서는 보통 static final을 사용해 상수를 선언하는 데, 상수만을 정의하는 클래스가 필요하다면 enum을 사용할 수 있습니다.

 

enum은 다음과 같이 사용될 수 있습니다.

 

public enum LevelOfXp {

    ONE(1L,100),
    TWO(2L,300),
    THREE(3L,600),
    FOUR(4L,1000),
    FIVE(5L,999999999);

    private final Long level;
    private final Integer requiredXp;
    
    LevelOfXp(Long level, Integer requiredXp) {
        this.level = level;
        this.requiredXp = requiredXp;
    }
}

 

Enum의 특징은 다음과 같습니다.

 

  • LevelOfXp.ONE와 같은 형태로 상수처럼 사용할 수 있습니다.
    • 여기서 LevelOfXp.ONE, LevelOfXp.TWO등은 힙 영역에 저장되어있습니다.
  • enum 클래스의 상수들은 힙 영역에 저장되어 있는 주솟값을 가리킵니다. 
  • enum은 고정된 상수들의 집합으로써, 런타임이 아닌 컴파일 타임에 모든 값을 알고있어야합니다.
    • 생성자가 private 접근 제어자를 가집니다.
    • 싱글톤을 보장합니다.
  • Enum 클래스는 상속을 지원하지 않습니다. -> 이미 java.lang.enum 클래스에서 상속을 받기 때문이다.(자바는 다중상속 지원x)

 

만약, 아래와 같이 Enum 클래스의 속성으로 count라는 변수가 추가되었다면, 멀티 쓰레드 환경에서 count가 공유되고 있기 때문에 조심해야합니다.

 

public enum LevelOfXp {

    ONE(1L,100),
    TWO(2L,300),
    THREE(3L,600),
    FOUR(4L,1000),
    FIVE(5L,999999999);

    private final Long level;
    private final Integer requiredXp;
    private int count;
    
    LevelOfXp(Long level, Integer requiredXp) {
        this.level = level;
        this.requiredXp = requiredXp;
    }
    
    public void plusCount(){
    	count++;
    }
}

 

 

그런데… 왜 Enum을 공부해야할 까??

 

Enum을 사용하면 아래와 같은 장점을 취할 수 있습니다. 

 

  • Enum을 사용하면, 서로 관련된 상수를 정의하기에 유용하다.
  • IDE의 적극적인 지원을 받을 수 있다.
  • 상태와 행위를 한 곳에서 관리할 수 있다.
  • 자바의 열거형은 타입에 안전한 열거형이라서 실제 값과 타입을 동시에 체크한다.
    • Enum의 열거형 상수 하나하나가 객체이다!

 

서로 관련된 상수를 정의하기 유용하다.

아래 코드는 제 프로젝트(sleeper) 코드의 일부입니다.

 

public enum XpPerLevel {

		ONE(1L,100),
		TWO(2L,300),
		THREE(3L,600),
		FOUR(4L,1000),
		FIVE(5L,999999999),
    ;

    private final Long level;
    private final Integer requiredXp;

    XpPerLevel(Long level, Integer requiredXp){
        this.level = level;
        this.requiredXp = requiredXp;
    }

    public static Long getCurrentLevel(Integer cumulativeXp, Long level){
        return Arrays.stream(XpPerLevel.values())
                .filter(x -> x.requiredXp <= cumulativeXp)
                .reduce((first,second) -> second)
                .map(XpPerLevel::getLevel)
                .orElse(level);
    }

}

 

레벨과 각각의 레벨의 최대 경험치 데이터가 관련되어 있다고 생각하여, enum을 사용하여 정의하였습니다.

 

상태와 행위를 한 곳에서 관리할 수 있다.

 

아래 코드는 제 프로젝트(sleeper) 코드의 일부입니다.

 

public enum RewardPerLevel {

		ONE(1L, x -> x*1),
		TWO(2L, x->x*2),
		THREE(3L, x->x*3),
		FOUR(4L, x-> x*4),
		FIVE(5L, x -> x*5);

    private final Long level;
    private final Function<Integer,Integer> rewardEquation;

    RewardPerLevel(Long level,Function<Integer,Integer> rewardEquation){
        this.level = level;
        this.rewardEquation = rewardEquation;
    }

    public static Integer calculateReward(Long level, Integer baseReward){
        return Arrays.stream(RewardPerLevel.values())
                .filter(x -> x.level == level)
                .findAny()
                .orElse(ONE)
                .rewardEquation
                .apply(baseReward);
    }
}

 

레벨에따라서, 리워드가 달라지기때문에 레벨에 따른 리워드를 나타낼 책임을 RewardPerLevel에 두었습니다.

그래서, 케릭터의 레벨 당 받을 수 있는 리워드를 enum을 사용해 정의했습니다.

그리고, ONE,TWO…가 각각 본인만의 계산식을 갖도록 하였습니다.

(Function 인터페이스 사용!)

 

 

이상입니다!!

 

728x90