Enum

기본적으둜 cλ‚˜ c++의 enumκ³Ό 같은 κΈ°λŠ₯을 μˆ˜ν–‰ν•˜λŠ” 클래슀둜 JDK 1.5이후에 생긴 ν΄λž˜μŠ€μ΄λ‹€.

cμ–Έμ–΄μ˜ C99 μ΄μ „μ—λŠ” booleanνƒ€μž…μ„ μ œκ³΅ν•˜μ§€ μ•Šμ•˜κΈ° λ•Œλ¬Έμ— λ‹€μŒκ³Ό 같이 μ‚¬μš©ν•˜κ³ λŠ” ν–ˆμ—ˆλ‹€.

typedef enum _boolean {
    FALSE,
    TRUE
} boolean;

#define FALSE 0
#define TRUE 1

Javaμ—μ„œμ˜ Enum νŠΉμ§•

Enum λΉ„κ΅μ‹œμ— 값이 μ•„λ‹Œ νƒ€μž…κΉŒμ§€λ„ 체크가 κ°€λŠ₯ν•˜κ³  Enum의 μƒμˆ˜κ°’μ΄ μž¬μ •μ˜ λ˜μ–΄λ„ λ‹€μ‹œ μ»΄νŒŒμΌν•˜μ§€ μ•ŠλŠ”λ‹€.

enum μ •μ˜ν•˜λŠ” 방법

enum Money { DOLLAR, WON, POUND, EURO, YEN, YUAN }

enum ν‚€μ›Œλ“œλ₯Ό μ΄μš©ν•˜μ—¬ μ •μ˜λ₯Ό ν•  수 있고 μ •μ˜λ₯Ό 어디에 ν•˜λŠλƒμ— 따라 λΆ„λ₯˜λ₯Ό ν•΄λ³΄μžλ©΄ 3κ°€μ§€μ •λ„λ‘œ λΆ„λ₯˜ν•  수 μžˆλ‹€.

1. λ³„λ„μ˜ Java 파일둜 μ •μ˜

[Money.java]

public enum Money {
    DOLLAR, WON, POUND, EURO, YEN, YUAN
}

[example.java]

public class example {
    public static void main(String[] args) {
        Money dollar = Money.DOLLAR;
        System.out.println(dollar);
    }
}

2. 클래슀 μ•ˆμ— μ •μ˜

public class example {
    public enum Money {
        DOLLAR, WON, POUND, EURO, YEN, YUAN
    }
    public static void main(String[] args) {
        Money dollar = Money.DOLLAR;
        System.out.println(dollar);
    }
}

3. 클래슀 밖에 μ •μ˜

enum Money {DOLLAR, WON, POUND, EURO, YEN, YUAN}

public class example {
    public static void main(String[] args) {
        Money dollar = Money.DOLLAR;
        System.out.println(dollar);
    }
}

μ •μ˜ μœ„μΉ˜μ— 따라 enum객체가 μƒμ„±λœ μœ„μΉ˜κ°€ λ‹€λ₯Έ 것을 λ³Ό 수 μžˆλ‹€.

enum μ‚¬μš©

Money.DOLLAR와 같이 Enum이름.μƒμˆ˜λͺ…μœΌλ‘œ μ‚¬μš©μ„ ν•  수 있으며 Money money = Money.DOLLAR와 같이 λ³€μˆ˜μ— ν• λ‹Ή 해쀄 μˆ˜λ„ μžˆλ‹€.

#include <stdio.h>

enum Money { DOLLAR, WON, POUND, EURO, YEN, YUAN }

int main() {
    enum Money dollar = DOLLAR;
    enum Money won = WON;

    if (dollar == 0) {
        printf("좜λ ₯1");        //좜λ ₯
    }
    if (won > dollar) {
        printf("좜λ ₯2");        //좜λ ₯
    }
    return 0;
}

C의 enum은 각 μƒμˆ˜κ°€ intν˜•μœΌλ‘œ μ €μž₯λ˜μ–΄ μ‚°μˆ μ—°μ‚°λ„ κ°€λŠ₯ν•˜κ³  μ•„λž˜μ™€ 같이 μƒμˆ˜λ¦¬ν„°λŸ΄κ³Ό 비ꡐ해도 κ°™κ²Œ λ‚˜μ˜€λŠ” λ¬Έμ œλ„ 생긴닀.

 public class example {
        private final static int DOLLAR = 0;
        private final static int WON = 1;
        private final static int POUND = 2;
        private final static int EURO = 3;
        private final static int YEN = 4;

        public static void main(String[] args) {
            System.out.println(DOLLAR == 0);
        }
    }

Enum이 없을 λ•Œ Javaμ—μ„œλ„ 이와 λΉ„μŠ·ν•˜κ²Œ class에 private final static intλ₯Ό μ΄μš©ν•΄μ„œ μƒμˆ˜κ°’μ„ μ •μ˜ ν•  수 μžˆμ—ˆλ‹€.

ν•˜μ§€λ§Œ 이 방법은 가독성에도 쒋지 μ•Šκ³  λ³€μˆ˜λͺ…이 κ²ΉμΉ  수 μžˆκ±°λ‚˜ μƒμˆ˜λ¦¬ν„°λŸ΄κ³Ό 비ꡐ가 λœλ‹€λŠ” 문제점이 μžˆλ‹€.

public class example {

    public static void main(String[] args) {
        Money dollar = Money.DOLLAR;
        Money won = Money.WON;

        System.out.println(dollar > won);   //error
        System.out.println(dollar == 0);    //error
    }
}

Java의 Enum은 각 μƒμˆ˜κ°€ μƒμˆ˜ κ·Έ 자체둜써 μž‘λ™μ„ ν•˜κ³  μžλ£Œν˜•μ΄ λ‹€λ₯΄κΈ° λ•Œλ¬Έμ— μ•„λž˜μ™€ 같이 λΉ„κ΅ν•˜λ €κ³  ν•˜λ©΄ compile errorκ°€ λœ¬λ‹€.

μƒμˆ˜μ— λ‹€λ₯Έ κ°’ μΆ”κ°€

enum Money {
    DOLLAR("λ‹¬λŸ¬"),
    WON("원"),
    POUND("νŒŒμš΄λ“œ"),
    EURO("유둜"),
    YEN("μ—”"),
    YUAN("μœ„μ•ˆ");

    private String hanguelName;

    private Money(){}
    private Money(String hanguelName){this.hanguelName = hanguelName;}

    public String getHanguelName(){
        return hanguelName;
    }
}

public class example {

    public static void main(String[] args) {
        Money dollar = Money.DOLLAR;
        Money won = Money.WON;

        System.out.println(dollar.getHanguelName());
        System.out.println(won.getHanguelName());

    }
}

클래슀의 μƒμ„±μžμ™€ 같은 λ°©λ²•μœΌλ‘œ 값을 ν• λ‹Ή 해쀄 수 있으며, getterλ₯Ό μ •μ˜ν•΄μ„œ 값을 μ°Έμ‘° ν•  μˆ˜λ„ μžˆλ‹€.

μ΄λ•Œ μƒμ„±μžλŠ” PRIVATE μ†μ„±μœΌλ‘œ 생성해주어야 ν•œλ‹€.

enumνƒ€μž…μ€ κ³ μ •λœ μƒμˆ˜λ“€μ˜ μ§‘ν•©μ΄λ―€λ‘œ 컴파일 νƒ€μž„μ— λͺ¨λ“  값을 μ•Œκ³  μžˆμ–΄μ•Όν•˜κΈ° λ•Œλ¬Έμ— λ‹€λ₯Έ ν΄λž˜μŠ€μ—μ„œ λ™μ μœΌλ‘œ 값을 정해쀄 수 μ—†κΈ° λ•Œλ¬Έμ— μƒμ„±μžλ₯Ό private둜 μ„€μ •ν•΄μ•Ό ν•˜κ³  finalκ³Ό 닀름이 없어진닀.

enum이 μ œκ³΅ν•˜λŠ” λ©”μ†Œλ“œ

values()

Enum의 λͺ¨λ“  μƒμˆ˜λ₯Ό λ°°μ—΄λ‘œ λ§Œλ“€μ–΄ λ°˜ν™˜ν•΄μ£ΌλŠ” ν•¨μˆ˜

 public class example {
    public static void main(String[] args) {
        for(Money money : Money.values()){
            System.out.println(money);      //μ°¨λ‘€λŒ€λ‘œ 좜λ ₯
        }
        System.out.println(Money.values()[1]); //WON 좜λ ₯
        System.out.println(Money.values() instanceof Object); //true
    }
 }

Money[]ν˜•νƒœμ˜ νƒ€μž…μœΌλ‘œ λ°˜ν™˜μ΄ λœλ‹€.

valuesOf()

λ§€κ°œλ³€μˆ˜λ‘œ Stringν˜•μ΄ 였며 이 λ§€κ°œλ³€μˆ˜μ™€ λ™μΌν•œ μ΄λ¦„μ˜ μƒμˆ˜λ₯Ό μ°Ύμ•„ μƒμˆ˜λ₯Ό λ°˜ν™˜ ν•˜κ³  μ—†λ‹€λ©΄ IllegalArgumentException μ˜ˆμ™Έλ₯Ό λ°œμƒμ‹œν‚¨λ‹€.

 public class example {
    public static void main(String[] args) {
        System.out.println(Money.valueOf("WON"));   //WON 좜λ ₯
        System.out.println(Money.valueOf("Rupee")); //IllegalArgumentException error
    }
 }

ordianal()

enum μƒμˆ˜κ°€ 0λΆ€ν„° μ‹œμž‘ν•˜μ—¬ μ •μ˜λœ μˆœμ„œλ₯Ό λ°˜ν™˜(int)ν•˜λŠ” ν•¨μˆ˜

public class example {
    public static void main(String[] args) {
        Money dollar = Money.DOLLAR;

        System.out.println(dollar.ordinal()); //0
    }
 }

ordinal은 Enum을 μ •μ˜ν•œ μˆœμ„œλ₯Ό λ°˜ν™˜ν•˜κΈ° λ•Œλ¬Έμ— cλ•Œμ²˜λŸΌ μƒμˆ˜λΌκ³  μƒκ°ν•˜λ©° μ‚¬μš©ν•˜μ§€ 말자.

ordinal은 EnumSetμ΄λ‚˜ EnumMap, JPAμ—μ„œ μ ‘κ·Όν•˜κΈ° μœ„ν•œ λ‚΄λΆ€ ν•¨μˆ˜λ‘œ κ°œλ°œμžλŠ” 거의 μ‚¬μš©ν• μΌμ΄ μ—†λŠ” λ©”μ„œλ“œμ΄λ‹€.

μ •μ˜ μˆœμ„œκ°€ λ°”λ€Œκ±°λ‚˜ 값이 μΆ”κ°€ 되면 μ „ν˜€ λ‹€λ₯Έ κ²°κ³Όκ°€ λ‚˜μ˜€κΈ° λ•Œλ¬Έμ΄λ‹€.

그런 이유둜 Spring Data JPAμ—μ„œ defaultλŠ” ordinal이기 λ•Œλ¬Έμ— Enumμˆœμ„œκ°€ 바뀐닀면 값이 μ•„μ˜ˆ 달라진닀. 컬럼으둜 Enum을 μ‚¬μš©ν•˜λ©΄ @Enumeratedλ₯Ό μ΄μš©ν•΄ String으둜 μ‚¬μš©ν•˜μž.

java.lang.Enum

enum ν΄λž˜λŠ” 기본적으둜 java.lang.EnumλΌλŠ” λΆ€λͺ¨ 클래슀λ₯Ό 상속 λ°›κ³  있고 μ΄λŠ” Objectλ₯Ό 상속받고 Comparableκ³Ό Serializableλ₯Ό implementsν•˜κ³  μžˆλ‹€.

protected Enum(String name, int ordinal) {
        this.name = name;
        this.ordinal = ordinal;
}

protectedν˜•μœΌλ‘œ μƒμ„±μžλ₯Ό ν•˜λ‚˜ 가지고 μžˆλŠ”λ° μ΄λŠ” κ°œλ°œμžκ°€ ν˜ΈμΆœν•  수 μ—†κ³  μ»΄νŒŒμΌλŸ¬μ— μ˜ν•΄ enum ν‚€μ›Œλ“œμ— λ°˜μ‘ν•˜μ—¬ μƒμ„±ν•˜κΈ° μœ„ν•¨μ΄λ‹€.

public String toString() {
    return name;
}

이 클래슀 내에 μžˆλŠ” public λ©”μ†Œλ“œ 쀑 Overrideν•΄μ„œ μ‚¬μš©ν• λ§Œν•œ λ©”μ„œλ“œλ‘œ 기본은 μƒμˆ˜ 이름을 λ°˜ν™˜ν•˜μ§€λ§Œ, enum을 μƒμ„±μ‹œ μΆ”κ°€ 값을 μ§€μ •ν•˜μ—¬ μƒμ„±ν–ˆλ‹€λ©΄ 이λ₯Ό Override해쀄 수 μžˆλ‹€.

컴파일 μ‹œμ˜ 객체 생성

final class Money extends Enum<Money> {
	private Money(String name, int ordinal) {
		super(name, ordinal);
	}

	public static final Status DOLLAR = new Status("DOLLAR", 0);
	public static final Status WON = new Status("WON", 1);
	public static final Status POUND = new Status("POUND", 2);
    public static final Status EURO = new Status("EURO", 3);
    public static final Status YEN = new Status("YEN", 4);


	private static final Status ENUM$VALUES[] = { DOLLAR, WON, POUND, EURO, YEN };
}

enum ν‚€μ›Œλ“œλ₯Ό μ‚¬μš©ν•˜μ—¬ μ—΄κ±°ν˜•μ„ μƒμ„±ν•˜λ©΄ 컴파일 μ‹œμ— μœ„μ™€ 같이 μ •μ˜κ°€ λœλ‹€.

EnumSet

Set μΈν„°νŽ˜μ΄μŠ€λ₯Ό κ΅¬ν˜„

EnumSet은 abstractν‚€μ›Œλ“œκ°€ μ•žμ— λΆ™μ–΄ 객체 생성이 λΆˆκ°€λŠ₯ν•˜κ³  of()와 같은 좔상 νŒ©ν† λ¦¬ λ©”μ„œλ“œμ—μ„œ μ‚¬μš©ν•˜λŠ” noneOf(class<E> elementType) λ©”μ„œλ“œκ°€ μ‘΄μž¬ν•˜μ—¬ 이λ₯Ό 톡해 κ΅¬ν˜„ 객체λ₯Ό 받을 수 μžˆλ‹€.

public static <E extends Enum<E>> EnumSet<E> noneOf(Class<E> elementType) {
        Enum<?>[] universe = getUniverse(elementType);
        if (universe == null)
            throw new ClassCastException(elementType + " not an enum");

        if (universe.length <= 64)
            return new RegularEnumSet<>(elementType, universe);
        else
            return new JumboEnumSet<>(elementType, universe);
    }

noneOf() λ©”μ„œλ“œλ₯Ό 보면 μ•Œκ² μ§€λ§Œ EnumSet 객체λ₯Ό λ°˜ν™˜ν•˜λŠ” 것이 μ•„λ‹Œ 이λ₯Ό 상속받은 ν΄λž˜μŠ€λ“€μ„ λ°˜ν™˜ν•˜κ³  μžˆλ‹€.

이 λ‘˜ 클래슀 λͺ¨λ‘ privateμ†μ„±μ΄λ―€λ‘œ 직접 μ‚¬μš©ν•  수 μ—†λ‹€.

  • μ‚¬μš©ν•  크기에 맞게 μ ν•©ν•œ κ΅¬ν˜„ 객체λ₯Ό 골라 μ€€λ‹€.

  • Enum의 μƒμˆ˜λ“€μ„ ν•˜λ‚˜ν•˜λ‚˜ Set에 λ‹΄λŠ” ν–‰μœ„λ₯Ό ν”Όν•  수 μžˆλ‹€.

  • EnumSet λ‚΄λΆ€ ν‘œν˜„μ€ λΉ„νŠΈ λ²‘ν„°λ‘œ ν‘œν˜„λœλ‹€. (μƒμˆ˜ κ°œμˆ˜κ°€ 64개 μ΄ν•˜λΌλ©΄ longλ³€μˆ˜ ν•˜λ‚˜λ‘œ ν‘œν˜„ν•œλ‹€.)

  • Enum μƒμˆ˜κ°€ μ„ μ–Έλœ μˆœμ„œ, 즉 ordinal() λ©”μ„œλ“œμ˜ λ°˜ν™˜λœ μˆœμ„œλ‘œ μˆœνšŒν•œλ‹€.

  • EnumSet iteratorλŠ” μ•½ν•œ 일관성을 μœ μ§€ν•˜μ—¬ ConcurrentModificationException을 λ°œμƒμ‹œν‚€μ§€ μ•ŠλŠ”λ‹€.

  • null μš”μ†ŒλŠ” μ‚½μž…μ΄ λ˜μ§€ μ•ŠλŠ”λ‹€.

  • 동기화가 λ˜μ§€ μ•ŠλŠ”λ‹€.

λ©”μ„œλ“œ

  • EnumSet.allOf(Class elementType) : λ§€κ°œλ³€μˆ˜μ˜ νƒ€μž…μ˜ λͺ¨λ“  μš”μ†Œλ₯Ό ν¬ν•¨ν•œ EnumSet을 λ°˜ν™˜

  • EnumSet.noneOf(Class elementType) : λ§€κ°œλ³€μˆ˜μ˜ νƒ€μž…μ˜ λΉ„μ–΄μžˆλŠ” EnumSetλ°˜ν™˜

  • EnumSet.of(E e1, E e2 ...) : μ§€μ •ν•œ λ§€κ°œλ³€μˆ˜λ₯Ό ν¬ν•¨ν•œ EnumSet을 λ°˜ν™˜

  • κ·Έ μ™Έ java.util.AbstractSet, java.util.AbstractCollection, java.lang.Object, java.util.Set으둜 λΆ€ν„° λ©”μ„œλ“œλ“€μ„ 상속받고 μžˆλ‹€.

    • 쀑볡 검사λ₯Ό μœ„ν•œ equals(),hashCode() ,add(),remove(),size(), toArray() => Object[] λ°˜ν™˜, iterator()λ“± μ‚¬μš© κ°€λŠ₯

EnumMap

Map μΈν„°νŽ˜μ΄μŠ€λ₯Ό κ΅¬ν˜„

  • Enum을 Key둜 μ΄μš©ν•˜λŠ” Map이닀.

  • Enum μƒμˆ˜λ‘œ null을 갖을 수 μ—†κΈ° λ•Œλ¬Έμ— null을 key둜 갖지 λͺ»ν•œλ‹€.

  • Enum은 정해진 μƒμˆ˜λ₯Ό μ‚¬μš©ν•˜κ³  단일 객체이기 λ•Œλ¬Έμ— ν•΄μ‹±ν•˜μ§€ μ•Šκ³  이미 μˆœμ„œκ°€ μ •ν•΄μ Έμžˆμ–΄ μ„±λŠ₯이 μ’‹λ‹€.

  • key와 valueκ°€ λ°°μ—΄λ‘œ κ΅¬μ„±λ˜μ–΄μžˆλ‹€.

  • EnumMap의 keyλŠ” ordianl둜 관리 되기 λ•Œλ¬Έμ— iteratorλŠ” μ•½ν•œ 일관성을 μœ μ§€ν•˜μ—¬ ConcurrentModificationException을 λ°œμƒμ‹œν‚€μ§€ μ•ŠλŠ”λ‹€.

  • 동기화가 λ˜μ§€ μ•ŠλŠ”λ‹€.

λ©”μ„œλ“œ

  • μƒμ„±μž : newν‚€μ›Œλ“œλ₯Ό μ΄μš©ν•΄ 생성할 수 있고 일반 Mapλ“€κ³Ό λ‹€λ₯΄κ²Œ enum νƒ€μž…μ„ νŒŒλΌλ―Έν„°λ‘œ λ„˜κ²¨μ£Όμ–΄μ•Ό ν•œλ‹€.

    • Map<Money,Integer> map = new EnumMap<>(Money.class);

  • clear() : λͺ¨λ“  μš”μ†Œ μ‚­μ œ

  • get(Object key) : key에 ν•΄λ‹Ήν•˜λŠ” value 리턴

  • put(K key, V value) : map에 데이터 μž…λ ₯

  • remove(Object key) : ν•΄λ‹Ήν•˜λŠ” keyκ°€ μžˆλ‹€λ©΄ μ‚­μ œ

  • equals(Object object) : κΈ°μ€€ Mapκ³Ό 같은지 비ꡐ

  • containsKey(Object key) / containsValue(Object value) : ν•΄λ‹Ήν•˜λŠ” key와 value κ°€ μžˆλ‹€λ©΄ true λ°˜ν™˜

  • size() : Map의 μš”μ†Œ 개수 λ°˜ν™˜

  • keySet() : Map에 μžˆλŠ” λͺ¨λ“  keyλ“€μ˜ Set viewλ₯Ό λ°˜ν™˜ν•œλ‹€. (λͺ¨λ“  key듀을 보여쀀닀.)

  • values() : Map에 μžˆλŠ” valueλ“€μ˜ Collection viewλ₯Ό λ°˜ν™˜ν•œλ‹€. (λͺ¨λ“  값듀을 보여쀀닀.)

μΆ”κ°€ λ‚΄μš©

type safety

Runtime이 μ•„λ‹Œ Complieνƒ€μž„μ— 문제λ₯Ό μž‘μ„ 수 μžˆλŠ” κ²ƒμœΌλ‘œ JVM은 μ»΄νŒŒμΌν• λ•Œ, νŠΉμ • 데이터 νƒ€μž…μ„ μ•Œ 수 μžˆμœΌλ‚˜ RUNμ‹œμ— νŠΉμ • 데이터가 쑴재 ν•˜μ§€ μ•ŠλŠ”λ‹€κ±°λ‚˜ ν•˜λŠ” λ¬Έμ œκ°€ 생길 수 μžˆλ‹€.

Enum을 μ‚¬μš©ν•˜λ©΄ μ˜€νƒ€λ°©μ§€λ₯Ό ν•  수 있고, μ»΄νŒŒμΌνƒ€μž„μ— μ—λŸ¬λ₯Ό μž‘μ•„μ£ΌκΈ° λ•Œλ¬Έμ— 디버깅도 μ‰¬μ›Œμ§„λ‹€.

Enumμ—μ„œ κ°’ μ…‹νŒ… 팁

Enum의 값을 좔가해쀄 λ•Œ 1,2,3같이 쒁은 숫자의 λ²”μœ„κ°€ μ•„λ‹Œ 10,20,30 같이 λ²”μœ„λ₯Ό 두고 μ„ μ–Έν•΄μ£Όμž.

μ–Έμ œ μ–΄λ–€μ΄μœ μ—μ„œ Enum에 값을 사이에 μΆ”κ°€ 해쀄지 λͺ¨λ₯΄κΈ° λ•Œλ¬Έμ΄λ‹€.


Reference

https://www.nextree.co.kr/p11686/

http://cris.joongbu.ac.kr/course/java/api/java/lang/Enum.html

https://javarevisited.blogspot.com/2014/03/how-to-use-enumset-in-java-with-example.html#axzz6kSbFjAwM

Last updated