| 일 | 월 | 화 | 수 | 목 | 금 | 토 |
|---|---|---|---|---|---|---|
| 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 |
| 28 | 29 | 30 |
Tags
- lv1
- 스프링 배치
- 로드밸런서
- redis
- 스케줄러
- Til
- 디자인 패턴
- 코드카타
- 스프링
- 트러블슈팅
- 추상클래스
- Effective Java
- GoF 23
- 토스
- DB
- 배치
- 백엔드
- 빌더 패턴
- java
- 김영한
- spring boot
- 템플릿 메서드 패턴
- 이펙티브 자바
- 계산기
- Spring Batch
- Spring
- 자바
- 성능 개선
- 프록시 패턴
- 프로그래머스
Archives
- Today
- Total
김코딩
이놈의 Enum, 그거 어떻게 쓰는건데? 본문
필자는 요즘 계산기 프로그램을 구현하는 과제를 수행 중입니다.
그 과정에서 사칙연산 기호를 관리하기 위해 enum을 활용하라는 요구사항이 있었는데요. 이번 글에서는 도대체 그 ENUM이라는 녀석이 무엇인지, 그리고 왜, 어떻게 써야 하는지 차근차근 알아보겠습니다.
Enum이란? – 이놈의 정체부터 알아보자
컴퓨터 프로그래밍에서 열거형(enumerated type, enumeration), 이넘(enum), 팩터(factor ← R 프로그래밍 언어와 통계학의 범주형 변수에서 부르는 명칭)는 요소, 멤버라 불리는 명명된 값의 집합을 이루는 자료형이다. 열거자 이름들은 일반적으로 해당 언어의 상수 역할을 하는 식별자이다. - wikipedia
Enum 정의하는 방법
상수의 이름을 나열하면 됩니다.
enum Operator {
ADD, // 덧셈
MINUS, // 뺄셈
MULTIPLY, // 곱셈
DIVIDE // 나눗셈
}
enum에서 정의된 상수를 사용하는 방법은 클래스의 static 변수를 참조하는 것과 같이 열거형이름.상수명 입니다.
(예시: Operator.ADD , Operator.MINUS, Operator.MULTIPLY, Operator.DIVIDE)
열거형 상수에는 필드를 가질 수 있습니다. 추가하고 싶은 필드를 정의하고 생성자의 인자로 추가 한 뒤 각각의 상수에 값을 입력하면 됩니다. 단, 열거형 상수에 값을 부여할 경우 이에 해당하는 생성자도 함께 정의해주어야 합니다.
enum OperatorType {
ADD('+'),
MINUS('-'),
MULTIPLY('*'),
DIVIDE('/');
private final char symbol;
// enum도 생성자를 가질 수 있어요! 단, 항상 private
OperatorType(char symbol) {
this.symbol = symbol;
}
public char getSymbol() {
return symbol;
}
}
enum에서 생성자를 정의한다면 private으로 선언해야 합니다. 다른 접근제어자로 선언 시 컴파일 에러가 발생합니다.
Enum? – 왜 사용하는건데?
우선 예시를 하나 보여드리겠습니다.
Enum을 사용하지 않았을 때 (문자열 비교)
아래는 주문 상태를 나타낼 때 문자열을 직접 비교해서 처리하는 코드입니다.
public class OrderService {
public void processOrder(String status) {
if (status.equals("PENDING")) {
System.out.println("주문 대기 중입니다.");
} else if (status.equals("SHIPPED")) {
System.out.println("배송 중입니다.");
} else if (status.equals("DELIVERED")) {
System.out.println("배송 완료!");
} else {
System.out.println("알 수 없는 상태입니다.");
}
}
}
- 오타가 나도 컴파일은 되지만, 실행 중 오류가 발생합니다.(런타임 오류)
- IDE의 자동 완성 기능을 쓸 수 없습니다.
- 상태가 추가되면 모든 코드에 하나하나 반영해줘야 합니다.
Enum을 사용했을 때
public enum OrderStatus {
PENDING,
SHIPPED,
DELIVERED
}
public class OrderService2 {
public void processOrder(OrderStatus status) {
switch (status) {
case PENDING -> System.out.println("주문 대기 중입니다.");
case SHIPPED -> System.out.println("배송 중입니다.");
case DELIVERED -> System.out.println("배송 완료!");
}
}
}

- 오타 방지: 사진에서 보이는 것 처럼 오타가 나면 IDE가 오류를 감지하여 오타를 방지할 수 있다.
- 유지보수 용이: 값 추가/변경 시 한 곳만 수정하면 된다.
- 가독성 향상: 의미 있는 이름으로 코드가 명확해진다.
Enum - 단지 값만 정리해주나?
사실 Enum에도 행동을 부여할 수 있습니다. Java에서는 람다식을 활용하여 각 enum 상수마다 다른 행동을 지정할 수 있게 해줍니다.
① 사칙연산을 if-else로만 처리할 때
public double calculate(double a, double b, char op) {
if (op == '+') return a + b;
else if (op == '-') return a - b;
else if (op == '*') return a * b;
else if (op == '/') return a / b;
else throw new IllegalArgumentException("잘못된 연산자입니다.");
}
- 연산자가 많아지면 if가 점점 길어진다.
- 연산자를 실수로 하나 빼먹으면 버그가 발생한다.
- 연산자 관련 코드가 흩어져있다.
② Enum으로 연산자 분리
public enum Operator {
ADD('+'), SUB('-'), MUL('*'), DIV('/');
private final char symbol;
Operator(char symbol) {
this.symbol = symbol;
}
}
- 연산자 기호를 Enum으로 모아서 관리가 편하게 되었다.
- 하지만 아직도 계산은 외부에서 if문이나 switch문을 활용하여 처리해야한다.
③ Enum 안에 계산 기능 넣기
enum Operator {
ADD('+') {
public double apply(double a, double b) { return a + b; }
},
MINUS('-') {
public double apply(double a, double b) { return a - b; }
},
MULTIPLY('*') {
public double apply(double a, double b) { return a * b; }
},
DIVIDE('/') {
public double apply(double a, double b) {
if (b == 0){
throw new ArithmeticException("분모는 0이 될 수 없습니다.");
} else{
return a / b;
}
}};
}
- 각 연산자에 고유 행동을 부여해줍니다.
- enum을 활용하여 연산 기능도 사용할 수 있습니다.
- 하지만 코드가 길고 중복이 많습니다.
④ Enum에 람다 사용
import java.util.function.DoubleBinaryOperator;
public enum Operator {
ADD('+', (a, b) -> a + b),
MINNUS('-', (a, b) -> a - b),
MULTIPLY('*', (a, b) -> a * b),
DIVIDE('/', (a, b) -> {
if (b == 0) throw new ArithmeticException("0으로 나눌 수 없습니다.");
return a / b;
});
private final char symbol;
private final DoubleBinaryOperator operation;
Operator(char symbol, DoubleBinaryOperator operation) {
this.symbol = symbol;
this.operation = operation;
}
public double apply(double a, double b) {
return operation.applyAsDouble(a, b);
}
}
DoubleBinaryOperator 함수형 인터페이스를 활용하여 람다식을 사용할 수 있습니다.
DoubleBinaryOperator란?
java.util.function 패키지에 있는 함수형 인터페이스입니다.
(매개변수 2개 → double, 반환도 double)
@FunctionalInterface
public interface DoubleBinaryOperator {
double applyAsDouble(double a, double b);
}
Enum이 제공하는 메서드
| 메서드 이름 | 설명 |
| toString() | ENUM 상수의 이름을 문자열로 반환한다. name() 메서드와 유사하지만, toString() 은 직접 오버라이드 할 수 있다. |
| name() | ENUM 상수의 이름을 문자열로 반환한다. |
| ordinal() | ENUM 상수의 선언 순서(0부터 시작)를 반환한다. |
| valueOf() | 인자로 받은 이름과 같은 Enum 값으로 반환한다. |
| values() | 선언된 모든 Enum 값을 순서대로 배열에 담아서 반환한다. |
정리 – Enum, 이놈 이제 좀 알겠니?
- enum은 관련된 상수들을 하나의 타입으로 묶어서 표현할 수 있는 유용한 도구입니다.
- 단순히 값만 저장하는 것이 아니라, 행동(메서드)까지 정의할 수 있어 데이터와 로직을 함께 묶을 수 있는 객체지향적인 코드를 작성할 수 있습니다.
- 문자열 비교처럼 오타 위험 없이, IDE의 자동완성도 지원받을 수 있어서 실수를 줄일 수 있습니다.
- 람다식, DoubleBinaryOperator와 함께 사용하면 간결하고 확장성 있는 코드도 만들 수 있습니다.
- Enum 내부에서는 values(), ordinal(), name() 같은 유용한 메서드들도 제공되어 활용도가 높습니다.