정의
- Enum이란 Enumeration의 앞 글자로, 열거라는 의미
- 관련된 상수들의 집합
- 자바에서는 final 로 String 과 같은 문자열이나 숫자들을 나타내는 기본 자료형의 값 고정 가능
- = 이렇게 고정된 값이 상수(constant)
- 어떤 클래스가 상수만으로 작성되어 있으면 반드시 class 로 선언할 필요는 X
- 이럴 때 클래스로 선언된 부분에 enum 이라 선언 시, 이 객체는 상수의 집합임을 명시적 표현하는 것
배경
- 기존에는 인터페이스나 클래스 내에서 상수 선언 후 관리해옴
- 클래스 내에서 선언 시, 네이밍이 겹치거나 불필요하게 상수가 많아지는 단점 있음
- 인터페이스로 관리 시 위 단점이 일부 상쇄되나, 여전히 IDE의 적극적 지원 부족 및 타입 안정성이 떨어진다는 단점 있었음➡️ 이를 보완하며 나온 것이 Enum
특징
클래스를 상수처럼 사용 가능
- Enum 도 생성자가 존재하나, Default 생성자는 private 로 되어 있음
- 이 생성자를 public 으로 변경 시, 컴파일 에러 발생
- 즉, 다른 클래스나 인터페이스에서의 상수 선언이 클래스 로드 시점에서 생성되듯,
- Enum 도 생성자가 존재하나, 클래스가 로드되는 시점에서 생성되기에 임의 생성하여 사용할 수 X
public enum Rank {
THREE(3, 4_000),
FOUR(4, 10_000),
FIVE(5, 30_000);
private final int match;
private final int money;
private int count;
Rank(int match, int money) { // Default 생성자는 private 으로 세팅됨
this.match = match;
this.money = money;
}
Enum 클래스 구현 , 상수값처럼 유일하게 하나의 인스턴스가 생성되어 사용됨
- Enum 클래스에서 선언한 상수들은 클래스가 로드될 때 하나의 인스턴스로 생성되어, 싱글톤(Singleton) 형태로 어플리케이션 전체에서 사용됨
- 싱글톤으로 사용되기에 각각의 Enum 인스턴스에 변수를 추가하여 사용하는 것은 멀티 쓰레드(Multi-Thread) 환경에서 위험할 수 있음
public enum Rank {
THREE(3, 4_000),
FOUR(4, 10_000),
FIVE(5, 30_000);
private final int match;
private final int money;
private int count;
Rank(int match, int money) {
this.match = match;
this.money = money;
}
public void plusCount() {
this.count++;
}
}
- 각 인스턴스에 count 라는 변수가 추가되어 있는데, 외부에서 각 등수에 맞게 plusCount() 호출 가능
- 그러나 멀티 쓰레드 환경에서는 각 인스턴스의 count가 공유되기에 조심해야 함
서로 관련된 상수값들을 모아 Enum 으로 구현 시 유용함
클래스와 같은 문법 체계 따름
상속 지원 X
- 모든 Enum 은 내부적으로 java.lang.Enum 클래스에 의해 상속됨
- 자바는 다중 상속 지원 X ➡️ Enum 은 다른 클래스 상속 불가
- 참고로 toString() 메서드는 상수의 이름을 리턴하도록 구현되어 있음
- 기존에 상속받고 있는 클래스가 있기에, 다중 상속은 불가하나 다양한 인터페이스 구현 가능
public static void main(String[] args) {
System.out.println(Rank.FIVE.toString()); // FIVE
}
Enum 내부 API
- java.lang.Enum 클래스를 기본적으로 상속받기에 몇 가지 메서드를 지원함
values()
- Enum 클래스가 가지고 있는 모든 상수값을 배열의 형태로 리턴
- 단순히 String 의 형태로 반환하는 것이 아닌, 인스턴스를 반환
- 즉, Enum 클래스가 가지고 있는 모든 인스턴스를 배열에 담아 반환
public static void main(String[] args) {
Rank[] values = Rank.values();
for(int i = 0; i < values.length; i++) {
System.out.println(values[i]);
}
// THREE
// FOUR
// FIVE
}
valueOf()
- String 을 파라미터로 받음
- 인자로 들어온 String 과 일치하는 상수 인스턴스 존재 시, 해당 인스턴스를 반환
- 단순히 문자열을 반환하는 것이 아닌, 인자로 들어온 문자열과 일치하는 인스턴스를 반환
public static void main(String[] args) {
System.out.println(Rank.valueOf("THREE")); // THREE
}
ordinal()
- Enum 클래스 내부에 있는 상수들의 인덱스(index)를 리턴
- 배열과 마찬가지로 0 부터 인덱스 시작
- 인덱스의 length = 상수의 개수 - 1
public static void main(String[] args) {
Rank[] values = Rank.values();
for(int i = 0; i < values.length; i++) {
System.out.println(values[i] + " 인덱스는 : " + values[i].ordinal());
}
// THREE 인덱스는 : 0
// FOUR 인덱스는 : 1
// FIVE 인덱스는 : 2
}
활용
데이터 그룹화 / 관리에 용이
- 관련되어 있으나 관련성을 표시하기 힘든 형태의 데이터를 한 곳에서 관리 가능
public enum Winner {
WINNER("승리", Arrays.asList("kyle","pobi","hello","world")),
LOSER("패배", Arrays.asList("hodol","dunddoung","rutgo");
private final String winner;
private final List<String> list;
Winner(String winner, List<String> list) {
this.winner = winner;
this.list = list;
}
}
- 상태와 행위를 한 곳에서 관리 가능
public boolean isWinner(String name) {
return WINNER.list.contains(name);
}
public int getWinnerSize() {
return WINNER.list.size();
}
- 클래스를 분리하지 않고도 두 데이터의 연관성을 명확하게 보여줌
- 어떤 수 입력 시, 해당 수와 일치하는 인스턴스를 반환하는 메소드 등
- 상태와 연관있는 행위도 한 곳에서 관리 가능
public enum Statistic {
THREE(3, 5000),
FOUR(4, 50_000),
FIVE(5, 1_500_000),
BONUS(5, 3_000_000),
SIX(6, 2_000_000_000);
private final int matchingNumbers;
private final int prize;
Statistic(int matchingNumbers, int prize) {
this.matchingNumbers = matchingNumbers;
this.prize = prize;
}
public static Statistic getRank(int numberOfMatch) {
return Arrays.stream(values())
.filter(statistic -> statistic.matchingNumbers == numberOfMatch)
.findFirst()
.orElseThrow(new IllegalArgumentException("일치하는 번호가 3미만입니다."));
}
Lambda 통한 Enum 사용 극대화
- 함수형 인터페이스 통해 Enum 의 각 상수 인스턴스도 더 능동적인 프로그래밍 가능
- 상수와 함수식 정보를 같이 관리 ➡️ 상태와 행위 모두 같은 곳에서 관리 가능
import java.util.function.BiFunction;
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 name;
private final BiFunction<Double, Double, Double> biFunction;
Operator(String name, BiFunction<Double, Double, Double> biFunction) {
this.name = name;
this.biFunction = biFunction;
}
public Double calculate(double a, double b) {
return this.biFunction.apply(a, b);
}
}
출처
https://velog.io/@kyle/%EC%9E%90%EB%B0%94-Enum-%EA%B8%B0%EB%B3%B8-%EB%B0%8F-%ED%99%9C%EC%9A%A9
'Backend > Java' 카테고리의 다른 글
[Java] Annotation (0) | 2023.12.05 |
---|---|
[Java] Exception (0) | 2023.12.05 |
[Java] Pass by Value vs. Pass by Reference (0) | 2023.12.05 |
[Java] 기본 자료형 & 참조 자료형 (0) | 2023.12.05 |
[자바의 신] 29장 (ongoing) (0) | 2022.08.31 |
댓글