모르지 않다는 것은 아는것과 다르다.

Java

ENUM 활용

채마스 2022. 3. 14. 18:20

개요

  • enum 을 자주 사용했지만, 꼭 필요한 경우와 장점을 확실하게 설명하지 못했다. 그래서 오늘 enum 에 대해서 좀더 자세히 공부하고 정리해 보려고 한다.
  • enum 을 사용하지 않았을 경우와 사용했을 경우를 비교해 보면서 enum 에 대해서 알아보자.

 

기존 코드

private void validateCreateDeveloperRequest(Developer developer, Integer experienceYears) {

        if (developer.getDeveloperLevel() == "junior"
                && experienceYears > 4) {
            throw new DMakerException(LEVEL_AND_EXPERIENCE_YEARS_NOT_MATCH);
        }

        if (developer.getDeveloperLevel() == "jungnior"
                && (experienceYears > 10 || experienceYears < 4)
        ) {
            throw new DMakerException(LEVEL_AND_EXPERIENCE_YEARS_NOT_MATCH);
        }

        if (developer.getDeveloperLevel() == "senior" && experienceYears < 11) {
            throw new DMakerException(LEVEL_AND_EXPERIENCE_YEARS_NOT_MATCH);
        }
    }
  • 위의 코드를 보면 가장먼저 "SENIOR", "JUNGIOR", "JUNIOR" 값을 상수 값으로 바꾸고 싶다는 생각이 들것이다.
  • 그렇다면 아래와 같이 리팩토링 할 수 있을 것이다.
public class DeveloperLevel {
    private static final String SENIOR = "senior";
    private static final String JUNGNIOR = "jungnior";
    private static final String JUNIOR = "junior";
}
private void validateCreateDeveloperRequest(Developer developer, Integer experienceYears) {

        if (developer.getDeveloperLevel() == DeveloperLevel.SENIOR
                && experienceYears < 10) {
            throw new DMakerException(LEVEL_AND_EXPERIENCE_YEARS_NOT_MATCH);
        }

        if (developer.getDeveloperLevel() == DeveloperLevel.JUNGNIOR
                && (experienceYears > 4 || rexperienceYears < 10)
        ) {
            throw new DMakerException(LEVEL_AND_EXPERIENCE_YEARS_NOT_MATCH);
        }

        if (developer.getDeveloperLevel() == DeveloperLevel.JUNIOR && rrexperienceYears > 4) {
            throw new DMakerException(LEVEL_AND_EXPERIENCE_YEARS_NOT_MATCH);
        }
    }
  • 위와 같이 상수값으로 변경함으로써, 개발자의 실수를 방지할 수 있고, 추후에 있을 변경에 대응하기 쉽다.
  • 하지만 상수값은 컴파일 하면 그 값이 클라이언트 파일에 그대로 새겨지기 때문에, 상수 값이 바뀌면 컴파일을 다시해야 된다는 단점이 있다.
  • 하지만 상수형은 상수가 많아질 경우 가독성이 떨어지고, 자료형에 대한 안정성을 보장 받을 수 없다.
  • 컴파일 단계에서 자료형에 대한 안정성을 보장 받지 못한다는 것은 치명적일 수 있다.
  • 그렇기 때문에 아래와 같이 java enum 을 이용해서 좀더 개선할 수 있다.
@AllArgsConstructor
@Getter
public enum DeveloperLevel {
    NEW("new"),
    JUNIOR("junior"),
    JUNGNIOR("jungnior"),
    SENIOR("senior")
    ;

    private final String description;
}
  • IDE 또는 컴파일 단계에서 지원을 받을 수 있다는 장점이 있다.
  • 또한 리팩토링의 유리하다. -> enum 이 내포하고 있는 값이 달라지더라도 enum 만 수정하면 되기 때문이다.
  • enum 은 불변객체로 생성되기 때문에 여러번 할당하더라도 비용부담이 발생하지 않는다.
  • 또한 인스턴스 생성과 상속을 방지하여 상수값의 타입안정성이 보장된다.

 

Enum 활용

  • 위의 코드를 enum 을 이용해서 좀더 리팩토링 할 수 있다.
  • 아래와 같이 enum 클래스를 수정한다.
@AllArgsConstructor
@Getter
public enum DeveloperLevel {
    NEW("new",0,0),
    JUNIOR("junior",1,4),
    JUNGNIOR("jungnior",5,9),
    SENIOR("senior",10,70)
    ;

    private final String description;
    private final Integer minExperienceYears;
    private final Integer maxExperienceTears;
}
  • Developer 객체의 developerLevel 속성을 String 이 아닌 enum 으로 추가해주면 아래와 같이 간결하게 수정할 수 있다.
private void validateCreateDeveloperRequest(Developer developer, Integer experienceYears) {

        if (experienceYears < developer.getDeveloperLevel().getMinExperienceYears() ||
                experienceYears < developer.getDeveloperLevel().getMinExperienceYears()){
            throw new DMakerException(LEVEL_AND_EXPERIENCE_YEARS_NOT_MATCH);
        }

        // if (developer.getDeveloperLevel() == DeveloperLevel.SENIOR
        //         && experienceYears < 10) {
        //     throw new DMakerException(LEVEL_AND_EXPERIENCE_YEARS_NOT_MATCH);
        // }

        // if (developer.getDeveloperLevel() == DeveloperLevel.JUNGNIOR
        //         && (experienceYears > 4 || rexperienceYears < 10)
        // ) {
        //     throw new DMakerException(LEVEL_AND_EXPERIENCE_YEARS_NOT_MATCH);
        // }

        // if (developer.getDeveloperLevel() == DeveloperLevel.JUNIOR && rrexperienceYears > 4) {
        //     throw new DMakerException(LEVEL_AND_EXPERIENCE_YEARS_NOT_MATCH);
        // }
    }
  • 위의 코드에서 주석으로 표시한 부분을 위의 코드처럼 줄일 수 있다.

 

함수형 프로그래밍 적용

@AllArgsConstructor
@Getter
public enum DeveloperLevel {
    NEW("new", years -> years == 0),
    JUNIOR("junior", years -> years <= 4),
    JUNGNIOR("jungnior", years -> years > 4 && years < 10),
    SENIOR("senior", years -> years >= 70)
    ;

    private final String description;
    private final Function<Integer, Boolean> validateFunction;

    public void validateExperienceYears(Integer years) {
        if (!validateFuction.apply(years))
            throw new DMakerException(LEVEL_AND_EXPERIENCE_YEARS_NOT_MATCH);
    }
}
  • 위와 같이 함수형 인터페이스를 적용할 수 있다.
private void validateCreateDeveloperRequest(Developer developer, Integer experienceYears) {

    developer.getDeveloperLevel().getValidateExperienceYears(experienceYears);

    // if (experienceYears < developer.getDeveloperLevel().getMinExperienceYears() ||
    //         experienceYears < developer.getDeveloperLevel().getMinExperienceYears()){
    //     throw new DMakerException(LEVEL_AND_EXPERIENCE_YEARS_NOT_MATCH);
    // }

}
  • 위의 코드에서 주석으로 표시한 부분을 위의 코드처럼 줄일 수 있다.

 

Enum 대표 메소드

values()

  • Enum 클래스에서 가지고 있는 모든 상수 인스턴스를 배열에 담아 반환한다.
DeveloperLevel[] values = DeveloperLevel.values();
for(int i=0;i<values.length;i++){
    System.out.println(values[i]);        // NEW, JUNIOR, JUNGNIOR, SENIOR
    System.out.println(values[i].getDescription()); // "new", "junior", "jungnior", "senior"
}

valueOf()

  • String을 매개변수로 받아 일치하는 상수 인스턴스를 반환한다. (없을 경우 런타임 에러 발생)
System.out.println(DeveloperLevel.valueOf("SENIOR"));
System.out.println(DeveloperLevel.valueOf("SENIOR").getDescription());

// RuntimeException
try{
    System.out.println(DeveloperLevel.valueOf("OH"));
}catch (IllegalArgumentException e){
    System.out.println("런타입 에러");
}
  • "OH" 라는 타입이 없으므로 IllegalArgumentException 를 반환합니다.

ordinal()

  • Enum 클래스 내부에 있는 상수들의 인덱스를 반환합니다.
System.out.println(DeveloperLevel.JUNIOR.ordinal()); // 1
  • JUNIOR 가 2번째이므로 인덱스 값인 1을 반환합니다.

 

 

REFERENCES

'Java' 카테고리의 다른 글

직렬화  (0) 2022.05.30
@SuppressWarnings  (0) 2022.05.30
Method Reference  (0) 2022.03.06
Collectors (JAVA STREAM)  (0) 2022.03.06
LazyEvaluation,Curry,IntStream  (0) 2022.03.06