AVA - 11 : 열거형

8935 단어 JavaJava

11 열거형

11.1 열거형(enum)이란

열거형은 쉽게 말하자면 일종의 상수 집합이다. 그리고 이러한 열거형은 다른 언어들에서도 쉽게 찾아볼 수 있다. 그리고 자바의 enum은 아래와 같은 특징과 장점이 있다.

  • 자바에서 enum 은 class 처럼 활용 가능(enum type)
  • type-safety한 연산 가능
  • enum 에 생성자, 필드 변수, 메서드 작성 가능
  • switch 문에 활용 용이
  • 열거형 값들 순회 가능
  • 다른 인터페이스들 implements 가능

11.1.1 enum 정의하기

public enum Day {
    SUNDAY, MONDAY, TUESDAY, WEDNESDAY,
    THURSDAY, FRIDAY, SATURDAY 
}

enum을 정의하는 방법은 위의 형태가 가장 기본적인 방법이다. 그리고 이를 다른 곳에서 아래와 같이 사용할 수 있다.

public class EnumTest {
    Day day;
    
    public EnumTest(Day day) {
        this.day = day;
    }
    
    public void tellItLikeItIs() {
        switch (day) {
            case MONDAY:
                System.out.println("Mondays are bad.");
                break;
                    
            case FRIDAY:
                System.out.println("Fridays are better.");
                break;
                         
            case SATURDAY: case SUNDAY:
                System.out.println("Weekends are best.");
                break;
                        
            default:
                System.out.println("Midweek days are so-so.");
                break;
        }
    }
    
    public static void main(String[] args) {
        EnumTest firstDay = new EnumTest(Day.MONDAY);
        firstDay.tellItLikeItIs();
        EnumTest thirdDay = new EnumTest(Day.WEDNESDAY);
        thirdDay.tellItLikeItIs();
        EnumTest fifthDay = new EnumTest(Day.FRIDAY);
        fifthDay.tellItLikeItIs();
        EnumTest sixthDay = new EnumTest(Day.SATURDAY);
        sixthDay.tellItLikeItIs();
        EnumTest seventhDay = new EnumTest(Day.SUNDAY);
        seventhDay.tellItLikeItIs();
    }
}

위의 결과는 아래와 같이 나온다.

Mondays are bad.
Midweek days are so-so.
Fridays are better.
Weekends are best.
Weekends are best.

하지만 우리가 앞서 확인했던 enum 의 특징 중에 enum 에는 필드와 생성자 그리고 메서드를 정의한다는 것이 있었다. 이를 확인하기 위해 작업별 시간과 임금을 열거형으로 통해 계산하는 예제가 있다.

class Solution {
    public enum WorkSchedule{
        CLEANING(10,7),
        WASHING(7,8);

        private final int time;
        private final int wage;

        WorkSchedule(int hour, int wage) {
            this.time = hour;
            this.wage = wage;
        }

        public int rest(int hours){
            return this.time - hours;
        }
    }

    public static void main(String args[]) {
        WorkSchedule clean = WorkSchedule.CLEANING;
        WorkSchedule wash = WorkSchedule.WASHING;
        System.out.println("Cleaning Total Wage : " + clean.time * clean.wage);
        System.out.println("Cleaning -2 hours : " + clean.rest(2) * clean.wage);
        System.out.println("Cleaning Original Time : " + clean.time);
        System.out.println("Washing Total Wage : " + wash.time * wash.wage);
        System.out.println("Washing -3 hours : " + wash.rest(3) * wash.wage);
        System.out.println("Washing Original Time : " + wash.time );
    }
}

결과는 아래와 같이 나온다.

Cleaning Total Wage : 70
Cleaning -2 hours : 56
Cleaning Original Time : 10
Washing Total Wage : 56
Washing -3 hours : 32
Washing Original Time : 7

여기서 enum 값이 데이터를 가지고 있는 객체처럼 사용되어지는 것을 확인할 수 있다. 그리고 enum 에 정의된 메서드를 외부에서 호출해서 내부의 값은 변경되지 않으면서도 조건에 따른 값을 계산할 수 있게 만들었다. 아래는 유의 사항이다.

  • enum 값이 먼저 선언되지 않으면 컴파일 에러 발생, 변수 선언처럼 마지막에 세미 콜론(;)
  • 각 enum 값은 별도의 메모리에 할당, 별도의 객체로 데이터 관리
  • new 키워드 사용없이 바로 enum 레퍼런스 사용

11.1.2 Type-Safety

앞서 enum 이 클래스처럼 사용가능하다는 것을 확인하였다면 type-safety한 연산이 왜 가능한지도 알 수 있다.

import java.time.MonthDay;
import java.util.Iterator;

class Solution {
    public enum Wage{
        TEN(10);
        private final int wage;
        Wage(int wage) {
            this.wage = wage;
        }
    }

    public enum Time{
        TEN(10);
        private final int time;
        Time(int time) {
            this.time = time;
        }
    }

    public static void main(String args[]) {
        System.out.print("is Wage.TEN equal to Time.TEN ? ");
        if(Wage.TEN.equals(Time.TEN))  System.out.println("YES");
        else System.out.println("NO");

        System.out.print("is Wage.TEN.wage == Time.TEN.time ? ");
        if(Wage.TEN.wage == Time.TEN.time) System.out.println("YES");
        else System.out.println("NO");

        System.out.println("Wage TEN is : " + Wage.TEN.wage);
        System.out.println("Time TEN is : "  + Time.TEN.time);
        System.out.println(Wage.TEN.getClass());
        System.out.println(Time.TEN.getClass());
    }
}

위의 결과는 아래와 같다.

is Wage.TEN equal to Time.TEN ? NO
is Wage.TEN.wage == Time.TEN.time ? YES
Wage TEN is : 10
Time TEN is : 10
class Solution$Wage
class Solution$Time

enum type이 다르면 enum 값의 리터럴이 같아도 equals() 연산을 하면 서로 다른 값이라 나온다.

11.2 enum 활용

11.2.1 java.lang.Enum

자바에서 enum 은 인터페이스를 implements 하는 것은 가능하다. 반대로 내부적으로 java.lang.Enum을 상속하고 있어 다른 클래스를 extends 할 수 없다. 하지만, 이를 상속받고 있기 때문에 3가지의 메서드를 사용할 수 있다.

  • values() : enum type 배열 반환
  • valueOf(String name) : name 에 해당하는 enum 값 찾기, 없으면 예외 발생
  • ordinal() : enum 순서 반환

11.2.2 enum 타입 배열, values()

이전에 다뤘던 enum의 특징 중에 순회할 수 있다는 것이 있었다. 이를 위해서는 enum 값들을 배열에 담아 반환하는 values()라는 메서드를 사용하면 된다.

class Solution {
    
    ...
    
    public static void main(String args[]) {
        WorkSchedule clean = WorkSchedule.CLEANING;
        WorkSchedule wash = WorkSchedule.WASHING;

        // values() 의 enum 타입 배열을 활용한 순회
        for(WorkSchedule work : WorkSchedule.values()) {
            System.out.println(work + " " + work.ordinal());
        }
    }
}

이전 예제와 같은 enum 을 사용하였고 순회하는 것을 보이기 위해 values()를 사용하는 코드를 추가하였다. 그 결과는 아래와 같다.

CLEANING 0
WASHING 1

enum에 값을 입력한 순서대로 CLEANING과 WASHING이 나온다. 그리고 ordinal()이라는 메서드를 활용해서 입력된 순서 확인도 가능하다.

11.2.3 enum 값 탐색, valueOf()

아래는 우리가 찾고자 하는 값이 enum 에 존재하면 해당 값을 반환하는 valuesOf()의 예제이다.

class Solution {

    ...

    public static void main(String args[]) {
        WorkSchedule clean = WorkSchedule.CLEANING;
        WorkSchedule wash = WorkSchedule.WASHING;

        System.out.println(WorkSchedule.valueOf("CLEANING"));
        System.out.println(WorkSchedule.valueOf("DRYING"));

    }
}

주의할 점은 찾고자 하는 값이 존재하지 않으면 IllegalArgumentException 예외를 던지기 때문에 예외 처리를 잘 해주어야 한다. 아래는 그 결과이다.

CLEANING
Exception in thread "main" java.lang.IllegalArgumentException: No enum constant Solution.WorkSchedule.DRYING
	at java.base/java.lang.Enum.valueOf(Enum.java:240)
	at Solution$WorkSchedule.valueOf(Solution.java:5)
	at Solution.main(Solution.java:27)

11.3 EnumSet

마지막은 EnumSet에 대한 정리이다. EnumSet은 Set인터페이스를 구현한 추상 클래스이다. 아래는 그 예제이다.

  • of() : enum 값들을 EnumSet에 추가할 수 있다
  • allOf(Enum Type) : 전체 값을 EnumSet에 추가할 수 있다.
import java.util.EnumSet;
import java.util.Set;

class Solution {
    public enum Wage {
        ONE(1),
        TWO(2),
        THREE(3),
        FOUR(4),
        FIVE(5);
        private final int wage;
        Wage(int wage) {
            this.wage = wage;
        }
    }


    public static void main(String args[]) {
        Set<Wage> set1 = EnumSet.of(Wage.FIVE,Wage.THREE);
        EnumSet<Wage> set2 = EnumSet.allOf(Wage.class);
        
        System.out.println(set1);
        System.out.println(set2);
        
    }
}

결과는 아래와 같이 나온다.

[THREE, FIVE]
[ONE, TWO, THREE, FOUR, FIVE]

EnumSet은 이렇게 enum 값들의 집합을 만들어서 필요한 연산을 할 때 유용하게 사용될 수 있다.

좋은 웹페이지 즐겨찾기