[Java] Enum

Junseo Kim·2021년 2월 20일
0

[Java]자바 기초

목록 보기
32/35

Enum

상수 객체의 모음집이며, 서로 관련있는 상수 값들을 모아서 사용할 때 유용하다.

상수의 역할을 하고, 각 상수가 객체이므로 프로퍼티나 메소드를 가질 수 있다.

상수의 역할을 하지만 클래스이기 때문에 생성자를 가짐(무조건 private)

내부 상수객체들은 각각 메모리에 하나만 존재하는 인스턴스이며, 만들어준 enum 클래스를 상속하고 있다. 따라서 enum 클래스 내부에 추상 메소드를 선언하면, 각 상수 객체에서 구현을 해줘야한다.

Enum 메소드

  • values(): 상수 객체들을 enum 타입 배열로 리턴해준다.
  • name(): 호출된 상수 객체의 이름을 String으로 바꿔서 리턴

Enum 활용

Enum을 활용해서 아래와 같은 상황에 조건문을 없애줄 수 있다.

public class Calculator {
    public int calculate(String op, int a, int b) {
        if ("+".equals(op)) {
            return a + b;
        } else if ("-".equals(op)) {
            return a - b;
        } else if ("*".equals(op)) {
            return a * b;
        } else if ("/".equals(op)) {
            return a / b;
        } else {
            throw new IllegalArgumentException();
        }
    }
}

위의 코드에서 +, -, *, /는 연산자라는 서로 관련있는 상수로 볼 수 있다. 따라서 enum 클래스로 사용할 수 있다.

public enum Operator {
    PLUS("+"),
    MINUS("-"),
    MULTIPLY("*"),
    DIVIDE("/");

    private final String operator;

    Operator(String operator) {
        this.operator = operator;
    }
}

하지만 단지 enum 클래스로 연산자들을 묶는다고 해도 조건문을 없앨 수 있는 것은 아니다.

이때 정적 팩토리 메소드를 사용하고, enum 클래스에서 각 상수객체에게 행동을 하도록 시킨다면 조건문을 없앨 수 있다.

public int calculate(String op, int a, int b) {
    Operator operator = Operator.from(op);
    return operator.calculate(a, b);
}

정적 팩토리 메소드로 Operator 타입의 인스턴스를 가져오고, 계산이라는 행동을 Operator 객체에 요청한다. 계산은 연산자가 두 수를 가지고 하는 행위이므로, 계산이라는 행동을 Operator 객체에서 처리하게 하는 것은 타당해보인다.

public enum Operator {
    PLUS("+") {
        @Override
        int calculate(int a, int b) {
            return a + b;
        }
    },
    MINUS("-") {
        @Override
        int calculate(int a, int b) {
            return a - b;
        }
    },
    MULTIPLY("*") {
        @Override
        int calculate(int a, int b) {
            return a * b;
        }
    },
    DIVIDE("/") {
        @Override
        int calculate(int a, int b) {
            return a / b;
        }
    };

    private final String operator;

    Operator(String operator) {
        this.operator = operator;
    }

    // 추상 메소드
    abstract int calculate(int a, int b);

    // 정적 팩토리 메소드
    static Operator from(String value) {
        for (Operator operator : values()) {
            if (operator.operator.equals(value)) {
                return operator;
            }
        }
        throw new IllegalArgumentException();
    }
}

처음에 살펴본 것 처럼 추상 메소드를 정의해주면, 각 상수 객체는 Operator를 상속하고 있기 때문에 추상 메소드를 구현해줘야한다. 각 상수가 객체이므로 메소드를 가질 수 있다는 점에 의해 각 상수 객체는 calculate 메소드를 override 하고 있다.

여기서 람다식을 사용해서 코드를 더 간결하게 만들 수도 있다.

public enum Operator {
    PLUS("+", (a, b) -> a + b),
    MINUS("-", (a, b) -> a - b),
    MULTIPLY("*", (a, b) -> a * b),
    DIVIDE("/", (a, b) -> a / b);

    private final String operator;
    private final BiFunction<Integer, Integer, Integer> calculate;

    Operator(String operator, BiFunction<Integer, Integer, Integer> calculate) {
        this.operator = operator;
        this.calculate = calculate;
    }

    static Operator from(String value) {
        for (Operator operator : values()) {
            if (operator.operator.equals(value)) {
                return operator;
            }
        }
        throw new IllegalArgumentException();
    }

    public int calculate(int a, int b) {
        return calculate.apply(a, b);
    }
}

모든 연산자는 2개의 정수 인자를 받아서 나름대로 계산하고 하나의 정수 값을 반환하므로 BiFunction<T, U, R> 함수형 인터페이스를 사용할 수 있다.

0개의 댓글