Java 에서 Enum 으로 분기 처리하기

자바의 Enum은 특별합니다.

상태를 담을 수 있습니다.


Enum을 이용하여 분기처리를 할수 있습니다.

  • JAVA의 Enum은 다른언어(예 : C++)들의 Enum과 다릅니다.
  • Enum 자체에서 행위를 관리할 수 있고, 이를 이용해서 if else를 대체할 수 있습니다.

자바 8 미만의 버전

  • 추상클래스를 만들어두고, 상수별 메소드를 구현하면 됩니다.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
package com.javapractice;

public class EnumPractice {
    public enum SpanEnum {
        SUMMER {
            @Override
            public void printSpan() {
                System.out.println("So Hot");
            }
        },
        WINTER {
            @Override
            public void printSpan() {
                System.out.println("So Cold");
            }
        };

        public abstract void printSpan();
    }

    public static void main(String[] args) {
        SpanEnum.valueOf("SUMMER").printSpan(); // So Hot
        SpanEnum.valueOf("WINTER").printSpan(); // So Cold
    }
}

  • 내부에 추상메소드를 만들어 둡니다.
  • 몸체를 오버라이딩 하여 하나씩 구현합니다.

자바 8 이상의 버전

람다식으로 구현합니다.

  • 추가예정

값을 받아서 리턴하기.

  • Enum은 new 로 객체 생성이 불가능합니다.
    • enum의 생성자는 디폴트로 private 입니다.
    • 즉 생성자에 public 접근제어자를 붙일 수 없습니다.
  • valueOf 를 이용하여 대응되는 상수에 접근할 수 있습니다.
  • inputValue("생성자에 들어가는 값") 과 같은 형식으로 작동합니다.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
package com.javapractice;

public class EnumPractice {
    public enum SpanEnum {
        SUMMER("So Hot"),
        WINTER("So Cold");

        private String span;

        SpanEnum(String span) {
            this.span = span;
        }

        public String getSpan() {
            return this.span;
        }
    }

    public static void main(String[] args) {
        SpanEnum spanEnum = SpanEnum.valueOf("SUMMER");
        //SpanEnum spanEnum = SpanEnum.SUMMER;
        System.out.println(spanEnum.getSpan());
        SpanEnum spanEnum2 = SpanEnum.SUMMER;
        System.out.println(spanEnum2.getSpan());
    }
}

  • valueOf 로 SUMMER 를 넣으면 이에 맞춰서 SpanEnum("So Hot") 이 되며, 해당 SpanEnum의 span에는 So Hot이 대입되게 됩니다.
    • SpanEnum.valueOf("SUMMER") 대신 Span.SUMMER으로도 가능합니다.

특정 입력에 따른 Enum을 반환 받아보자.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
public enum Rank {
    RANK1(5, 5000),
    RANK2(4, 4000),
    RANK3(3, 3000),
    RANK4(2, 2000),
    FAIL(0, 0);

    private int prizeMoney;
    private int matchCount;

    Rank(final int matchCount, final int prizeMoney) {
        this.matchCount = matchCount;
        this.prizeMoney = prizeMoney;
    }
}
  • 다음과 같은 경우에서 matchCount에 맞는 RANKprizeMoney를 가져오길 원하는 경우를 예시를 통해 설명해 보겠습니다.

RANK를 가져오기

getRank()

1
2
3
4
5
6
public static Rank getRank(final int matchCount) {
        return Arrays.stream(values())
                .filter(rank -> rank.matchCount == matchCount)
                .findFirst()
                .orElse(FAIL);         
}
1
Rank rank = Rank.getRank(2);
  • 다음과 같이 stream을 이용해 matchCount에 맞는 Rank를 가져올 수 있습니다.
1
2
3
4
5
6
7
8
public static Rank getRank(final int matchCount) {
    for(Rank rank : Rank.values()){
        if(rank.matchCount == matchCount) {
            return rank;
        }
    }
    return Rank.FAIL;
}
  • for 문으로는 위와 같이 구현이 가능합니다.
    • RANK 상수는 위에서부터 아래로 탐색하게 됩니다.

Money를 가져오기

getPrizeByMathCount

1
2
3
public int getPrizeMoney() {
    return prizeMoney;
}
1
2
Rank rank = Rank.getRank(2);
System.out.println(rank.getPrizeMoney());
  • Rank를 가져오고 Rank에서 getPrizeMoney()메소드를 호출해 Money를 가져오는 방법도 존재합니다.
  • 하지만 다음과 같은 방법은 메소드를 호출해야 한다는 번거로움이 존재합니다.

1
2
3
4
5
6
7
public static int getPrizeByMathCount(final int matchCount){
    return Arrays.stream(values())
            .filter(rank -> rank.matchCount == matchCount)
            .findFirst()
            .orElse(FAIL)
            .prizeMoney;
}
  • 다음과 같은 방법으로 한번에 prizeMoney를 가져올 수 있습니다.

Enum 생성자는 단 한번만 호출됩니다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
enum SpanEnum {
    SPRING(),
    SUMMER(),
    WINTER();

    SpanEnum() {
        System.out.println("run");
    }
}

// 하나의 경우
public class EnumPractice {
    public static void main(String[] args) {
        SpanEnum spanEnum1 = SpanEnum.SPRING;   // "run" 이 3번 호출됩니다.
    }
}

public class EnumPractice {
    public static void main(String[] args) {
        SpanEnum spanEnum1 = SpanEnum.SPRING;   // "run" 이 3번 호출됩니다.
        SpanEnum spanEnum2 = SpanEnum.SUMMER;   // "run" 이 호출되지 않습니다.
    }
}

image

  • 이것은 위에서 대충 이야기하고 넘어간 Enum의 생성자가 왜 private 인지에 대해서 생각해봐야 합니다.
  • enum의 생성자는 고정된 상수들의 집합이라, 컴파일 타입에 모든값을 알아야 하고 변경되어선 안됩니다.

Reference

  • https://woowabros.github.io/tools/2017/07/10/java-enum-uses.html
  • https://velog.io/@ljinsk3/Enum-%EC%82%AC%EC%9A%A9-%ED%95%98%EA%B8%B01-Basic
  • https://stackoverflow.com/questions/7113363/private-enum-constructor