자바(Java)

[자바] 자바 Enum

Ash_jisu 2023. 9. 27. 18:02

열거형

열거형이란

서로 관련된 상수를 편리하게 선언하기 위한 것으로 여러 상수를 정의할 때 사용하면 유용하다.

자바 1.5전에는 C언어와 달리 별도의 열거형이라는 것이 존재하지 않았으나 1.5부터 새로 추가되었다.

enum은 여러 상수를 정의한 후, 정의된 것 이외의 값은 허용하지 않는다.

 

아래는 Enum이 컴파일러에 의해 정의되는것부터 Enum의 상수들이 바이트코드로 포함되고 이후 

런타임때 클래스 로더에 의해 로드되는 과정을 아래 그림으로 표현했다

과정

 

 

사용 이유와 장점

  1. 코드 가독성 향상: Enum은 관련된 상수들을 그룹화하고 이름을 부여하여 코드의 가독성을 향상시킵니다. 이 경우, 각 단위(Unit)는 Enum 상수로 정의되어 있으며, 코드에서 해당 상수를 사용하면 의미가 명확하게 전달됩니다.
  2. 타입 안정성(Type Safety): Enum을 사용하면 컴파일러가 타입 안정성을 검사할 수 있으므로 잘못된 단위나 값을 사용하는 오류를 미리 방지할 수 있습니다.
  3. 상수값 관리: Enum을 사용하면 관련된 상수 값을 한 곳에서 중앙 관리할 수 있습니다. 이 코드에서는 각 단위의 이름과 Enum 값이 매핑되어 있으므로, 단위의 이름을 변경해야 할 때 Enum 값만 수정하면 됩니다.
  4. 코드 유지 및 확장 용이성: 새로운 단위를 추가하거나 기존 단위를 수정하기 쉽습니다. Enum에 새로운 상수를 추가하거나 수정하면 코드의 다른 부분에서 변경이 필요하지 않습니다.
  5. 코드 품질 향상: Enum을 사용하면 상수와 그에 따른 동작을 묶어서 정의할 수 있으므로, 코드의 일관성을 유지하고 오류 가능성을 줄일 수 있습니다.

 

단점

  1. 번거로운 선언: 열거형 상수를 선언할 때 모든 상수를 나열해야 하며, 상수가 많은 경우 선언이 번거로울 수 있습니다.
  2. 확장성의 한계: 열거형은 런타임 중에 새로운 상수를 동적으로 추가하는 것이 불가능합니다. 따라서 Enum에 새로운 상수를 추가하려면 소스 코드를 수정하고 다시 컴파일해야 합니다.
  3. 메모리 사용량: 열거형은 각 상수가 하나의 인스턴스이므로 모든 상수가 메모리에 상주하게 됩니다. 이는 Enum이 상수 개수가 많은 경우 메모리 사용량을 높일 수 있습니다.
  4. 상속의 제한: 열거형은 다른 클래스를 상속할 수 없습니다. Java에서는 단일 상속만 허용하므로 열거형은 이미 다른 클래스를 상속할 수 없습니다.
  5. 유연성 부족: Enum은 정적이며 상수가 고정되어 있기 때문에 동적으로 변하는 데이터를 표현하기에는 적합하지 않습니다.
  6. 복잡한 로직의 표현 어려움: 열거형은 주로 상수 집합을 표현하는 데 사용되며, 복잡한 로직이나 동작을 표현하기에는 제한적일 수 있습니다.

 


Enum정의하는 법

jdk1.5이전 열거형처럼 사용할려면 아래와 같이 코드를 짜야했다.

public class Day {  
    public static final int MONDAY = 1;
    public static final int TUESDAY = 2;
    public static final int WEDNESDAY = 3;
    public static final int THURSDAY = 4;
    public static final int FRIDAY = 5;
    public static final int SATURDAY = 6;
    public static final int SUNDAY = 7;
}

 

 

정의와 사용

  • enum 열거형 이름{‘상수명1, 상수명2}
public enum Day {
    MONDAY,  //대문자가 관례
    TUESDAY,
    WEDNESDAY,
    THURSDAY,
    FRIDAY,
    SATURDAY,
    SUNDAY;
}

 

enum 상수형으로 선언 하기

import enum_example.Day;

public class Main {
    public static void main(String args[]) {
        Day today = Day.MONDAY;   //Day형 today를 Day형 상수 Monday로 선언
        String str = today.toString();
        System.out.println(str);    
        System.out.println(today);  //알아서 toString()변환해줌
    }
}

결과

출력결과

 

한가지 알아둬야할게 출력문에서 Enum의 상수를 지칭하는 Enum형 변수가 출력문에 들어가면 자동으로 문자열로 바뀐다는것이다.(처음에 today를 문자열로 안바꾸고 출력했는데 에러가 안떠서 당황)

 

 

열거형 비교

열거형 상수간의 비교에는 '=='를 사용할 수 있다. '=='로 비교한다는것은 빠른 성능을 제공한다는 뜻이다.

compareTo 도 사용 가능하지만 '<','>'같은 비교연산자는 사용불가능하다 . compareTo()는 비교대상이

같으면 0, 왼쪽이 크면 양수, 오른쪽이 크면 음수를 반환한다

 

Enum클래스내의 CompareTo메서드

상수 정의된 순서를 구하고자 ordinal메서드를 사용하는 것을 알 수있다. 아래에서 설명할 예정

 

 

CompareTo 사용예시

import enum_example.Day;

public class Main {
    public static void main(String args[]) {
        Day today = Day.TUESDAY;
        Day tomorrow = Day.WEDNESDAY;

        // compareTo 메서드를 사용하여 두 Enum상수를 비교
        int comparison = today.compareTo(tomorrow);

        if (comparison < 0) {
            System.out.println(today+"기준으로 "+tomorrow+"는 내일이다");
        } else if (comparison > 0) {
            System.out.println(today+"기준으로 "+tomorrow+"는 어제이다");
        } else {
            System.out.println(today+"기준으로 "+tomorrow+"는 같은 요일이다");
        }
    }
}

출력

출력결과

 

 

 

+switch문에도 사용이 가능하다

public class Main {
    public static void main(String[] args) {
        DayOfWeekEnum today = DayOfWeekEnum.MONDAY;

        switch (today) {
            case MONDAY:
                System.out.println("오늘은 월요일입니다.");
                break;
            case TUESDAY:
                System.out.println("오늘은 화요일입니다.");
                break;
            case WEDNESDAY:
                System.out.println("오늘은 수요일입니다.");
                break;
            default:
                System.out.println("올바른 요일이 아닙니다.");
                break;
       }
}

 

 

 


Enum이 제공하는 메서드

 

4가지

  • Class<E> getDeclaringClass(): 열거형의 객체를 반환한다
  • String name(): 이름을 문자열로 반환
  • int ordinal(): 열거형 상수가 정의된 순서를 반환한다
  • T valueOf(Class<T> enum Type, String name): 지정된 열거형에서 name과 일치하는 열거형 상수를 반환한다

 

Enum클래스 문서

 

 

사용 예시

 

Class getDeclaringClass()

- 좋은 예시는 아니지만 이런식으로 enum이 속해있는 클래스를 알려준다

import enum_example.Day;
import enum_example.PizzaStoreClosureDay;

public class Main {
    public static void main(String args[]) {
        Day today = Day.WEDNESDAY;
        Day tomorrow = Day.THURSDAY;

        PizzaStoreClosureDay store1ClosureDay1 = PizzaStoreClosureDay.WEDNESDAY;

        Class<? extends Enum> declaringClass = store1ClosureDay1.getDeclaringClass();  //대체 휴무일이 수요일인 상점1의 클래스는 어디냐? 피자집이여 치킨집이여?
        System.out.println("휴무일에 수요일이 속해있는 클래스는 "+declaringClass+" 이다");
    }
}

출력결과

 

 

 

String name()

import enum_example.Day;

public class Main {
    public static void main(String args[]) {
        Day today = Day.WEDNESDAY;
        Day tomorrow = Day.THURSDAY;

        String dayName = Day.MONDAY.name();
        System.out.println(dayName);
    }
}

출력결과

 

 

ordinal

import enum_example.Day;

public class Main {
    public static void main(String args[]) {
        Day today = Day.WEDNESDAY;
        Day tomorrow = Day.THURSDAY;

        int dayNum = Day.FRIDAY.ordinal();
        System.out.println(dayNum);
    }
}

 

출력 결과

 

 

T valueOf(Class enum Type, String name)

import enum_example.Day;

public class Main {
    public static void main(String args[]) {
        String todayStr = "WEDNESDAY";  //오늘 요일을 문자열로 선언
        Day today = Enum.valueOf(Day.class, todayStr);   //해당하는 Enum클래스와 문자열대입

        System.out.println(today);
    }
}

출력 결과

 

렇다면 enum에 해당하지 않는 문자열이 들어가있다면 어떻게 될까? todayStr ="WEDNESDA" - 일부러 Y뺌

아래와 같이 해당하는 enum이 없다고 뜬다

 

 

추가

values() 메서드

  • 이 메서드를 호출하면 Enum 클래스에 정의된 모든 상수가 배열로 반환되며, 배열의 순서는 Enum 상수가 정의된 순서와 동일하다.  Enum상수를 반복할때 유용하다
import enum_example.Day;

public class Main {
    public static void main(String[] args) {
        Day[] days = Day.values();
        for (Day day : days) {
            System.out.println(day);
        }
    }
}

출력 결과

 

 


java.lang.Enum

자바의 java.lang.Enum 클래스 문서를 보면 java.lang.Enum 클래스가 모든 Java 언어 열거형 타입의 공통 기본 클래스임을 나타낸다. 즉, 모든 열거형 타입은 이 클래스를 기반으로 하여 상속받는다

따라서 Enum클래스를 상속받고 본인만의 Enum클래스 형식을 만드는 것도 가능하다

 

아래 블로그에 가보면 자세한 예시가 나와있다

참고: https://b-programmer.tistory.com/262

 

 


EnumSet

EnumSet은 enum클래스와 함께 작동하는 특수 SEt컬렉션이다. Set 인터페이스를 구현하고 AbstractSet에서 확장된다

참고: https://www.baeldung.com/java-enumset

 

 

고려사항

1. 열거형 값만 포함 할 수 있으며, 모든 값은 동일한 열거형이어야 한다.

2. null을 추가할 수 없다.

 

 

EnumSet 사용 예제

EnumSet생성

import enum_example.Day;
import java.util.EnumSet;

public class Main {
    public static void main(String args[]) {
        // EnumSet 생성
        EnumSet<Day> workingDays = EnumSet.of(Day.MONDAY, Day.TUESDAY, Day.WEDNESDAY, Day.THURSDAY, Day.FRIDAY);

        //순회
        for (Day day : workingDays) {
            System.out.println(day);
        }
    }
}

출력 결과

 

add, remove 예시EnumSet에 들어가있는 열거형에 해당하는 enum을 추가하거나 제거할수 있다

import enum_example.Day;
import java.util.EnumSet;

public class Main {
    public static void main(String args[]) {
        // EnumSet 생성
        EnumSet<Day> workingDays = EnumSet.of(Day.MONDAY, Day.TUESDAY, Day.WEDNESDAY, Day.THURSDAY, Day.FRIDAY);

        //일하는 요일중에 월요일이 토요일로 변경되었다고 가정
        workingDays.add(Day.SATURDAY);
        workingDays.remove(Day.MONDAY);

        //순회
        for (Day day : workingDays) {
            System.out.println(day);
        }
    }
}

출력 결과

 

 

allOf(), noneOf()예시allOf: 열거형의 모든 요소를 포함하는 EnumSet생성noneOf: 빈 열거형을 갖는 EnumSet생성

import enum_example.Day;
import java.util.EnumSet;

public class Main {
    public static void main(String args[]) {
        // EnumSet 생성
        EnumSet<Day> antWorkingDays = EnumSet.allOf(Day.class);
        EnumSet<Day> baeksu = EnumSet.noneOf(Day.class);

        //순회
        System.out.println("개미 출근 요일");
        for (Day day : antWorkingDays) {
            System.out.println(day);
        }
        System.out.println("\n백수 출근 요일");
        for (Day day : baeksu) {
            System.out.println(day);
        }
    }
}

출력 결과

 

이외에도 포함되어있는 특정 요소를 찾는 contains(), 다른 EnumSet의 모든 요소를 복사하는 copyOf()등의 메서드가 있다

 


describeConstable()메서드 

공식문서 참고: https://docs.oracle.com/en/java/javase/17/docs/api/java.base/java/lang/Enum.html

자바 12에 추가되었고 인스턴스에 대한 열거형 설명자를 EnumDesc생성할 수 있으면 반환하고, 생성할 수 없으면 빈 값을 반환한다

 

아래는 사용예시다

 

package enum_example;

import java.util.Optional;

public enum Day {
    MONDAY("한주의 시작"),
    TUESDAY("주의 이틀차"),
    WEDNESDAY("한주의 중간"),
    THURSDAY("한주의 중간이 지나감"),
    FRIDAY("평일의 끝"),
    SATURDAY("주말"),
    SUNDAY("주말");

    private final String description;

    Day(String description) {
        this.description = description;
    }

    public Optional<Enum.EnumDesc<Day>> describeConstable() {
        return Optional.of(Enum.EnumDesc.of(name(), description));
    }


    public static void main(String[] args) {
        Day day = Day.WEDNESDAY;

        // describeConstable() 메서드를 사용하여 상수 설명을 얻음
        Optional<Enum.EnumDesc<Day>> description = day.describeConstable();

        // 설명이 있는 경우 출력
        description.ifPresent(desc -> {
            System.out.println("Day: " + desc);
        });
    }
}

 

 

 

 


참고

자바의 정석(저자 남궁인)

 

오라클 공식문서

 

https://five-cosmos-fb9.notion.site/Enum-6ffa87530c424d8ab7a1b585bfb26fa2

 

https://b-programmer.tistory.com/262