[Java] 열거형(Enum)
인프런 얄코의 제대로 파는 자바, 생활코딩의 유튜브 상수와 enum 강의를 듣고 정리한 글입니다.
열거형이란?
열거형(enum)은 서로 관련된 상수들을 하나의 그룹으로 묶어 정의할 수 있는 특수한 클래스이다. 주로 상수값 집합을 표현할 때 사용되며, 타입 안정성과 코드 가독성을 높이는 데 유용하다.
1
2
3
4
String mode = "LIGHT";
mode = "DARK";
mode = "liGhT"; // 💥
지정된 선택지 내(LIGHT, DARK)의 값을 받을 변수 사용 시
잘못된 범위의 값 입력에 대해 대응하기가 번거롭기 때문에 실수를 방지할 방법이 없다.
이를 해결하기 위해 enum 이라는 클래스가 나온 것이다.
enum 탄생 배경
1️⃣ 클래스 내부의 상수
1
2
3
4
5
6
7
8
9
10
11
public class Demo {
// 과일
private final static int APPLE = 1;
private final static int PEACH = 2;
private final static int BANANA = 3;
// 회사
private final static int GOOGLE = 1;
// private final static int APPLE = 2; // ⚠️ 상수 중복
private final static int ORACLE = 3;
}
상수명의 규칙을 통해서 에러를 제거
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
public class Demo {
private final static int FRUIT_APPLE = 1;
private final static int FRUIT_PEACH = 2;
private final static int FRUIT_BANANA = 3;
private final static int COMPANY_GOOGLE = 1;
private final static int COMPANY_APPLE = 2;
private final static int COMPANY_ORACLE = 3;
public static void main(String[] args) {
int type = FRUIT_APPLE;
switch (type) {
case FRUIT_APPLE:
System.out.println(57 + "kcal");
break;
case FRUIT_PEACH:
System.out.println(34 + "kcal");
break;
case FRUIT_BANANA:
System.out.println(93 + "kcal");
break;
}
}
}
2️⃣ 인터페이스로 분리
인터페이스라고 하는 문법적인 것을 이용하여 가독성을 해결
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
31
// 💡 인터페이스 안의 멤버는 `public final static`을 암시
interface FRUIT {
int APPLE = 1,
int PEACH = 2,
int BANANA = 3
}
interface COMPANY {
int GOOGLE = 1,
int APPLE = 2,
int ORACLE = 3
}
public class Demo {
public static void main(String[] args) {
int type = FRUIT.APPLE;
switch (type) {
case FRUIT.APPLE:
System.out.println(57 + "kcal");
break;
case FRUIT.PEACH:
System.out.println(34 + "kcal");
break;
case FRUIT.BANANA:
System.out.println(93 + "kcal");
break;
}
}
}
💥 문제점
1
2
3
4
5
6
7
8
9
10
11
interface FRUIT {
int APPLE = 1,
int PEACH = 2,
int BANANA = 3
}
interface COMPANY {
int GOOGLE = 2,
int APPLE = 1,
int ORACLE = 3
}
1
2
3
4
5
public static void main(String[] args) {
if (FRUIT.APPLE == COMPANY.APPLE) { // true
System.out.println("과일애플과 기업애플은 같습니다.");
}
}
FRUIT.APPLE 과 COMPANY.APPLE 은 비교를 할 수 없는 대상이지만 true 가 나오는 것… (데이터타입이 int 이기 때문)
이것은 컴파일 에러가 발생하지 않기 때문에 앱을 구동하는 과정에서
에러가 발생하면 이 에러는 찾기가 매우 어렵다.
3️⃣ 클래스로 분리
데이터타입이 각각 다르기 때문에 비교가 불가능하도록 해결했지만, switch문에서 사용할 수 없다.
switch 문의 조건으로는 몇가지 제한된 데이터 타입만을 사용할 수 있다.
byte,short,char,int,enum,String,Character,Byte,Short,Integer
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
31
32
33
34
class Fruit {
// 데이터타입은 같지만 각각 서로 다른 인스턴스를 가진다.
public static final Fruit APPLE = new Fruit();
public static final Fruit PEACH = new Fruit();
public static final Fruit BANANA = new Fruit();
}
class Company {
public static final Company GOOGLE = new Company();
public static final Company APPLE = new Company();
public static final Company ORACLE = new Company();
}
public class Demo {
public static void main(String[] args) {
// ✅ 데이터타입이 다르므로 컴파일 에러 발생
if (FRUIT.APPLE == COMPANY.APPLE) {
System.out.println("과일애플과 기업애플은 같습니다.");
}
Fruit type = Fruit.APPLE;
switch (type) { // 💥 에러 발생
case FRUIT.APPLE:
System.out.println(57 + "kcal");
break;
case FRUIT.PEACH:
System.out.println(34 + "kcal");
break;
case FRUIT.BANANA:
System.out.println(93 + "kcal");
break;
}
}
}
4️⃣ enum
위 문제들을 해결하기 위해 자바에서 문법적으로 지원
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
enum Fruit {
APPLE, PEACH, BANANA
}
enum Company {
GOOGLE, APPLE, ORACLE
}
public class Demo {
public static void main(String[] args) {
Fruit type = Fruit.APPLE;
switch (type) {
// 💡 switch문으로 전달한 데이터타입을
// switch문은 알고있기 때문에 상수명만 작성
case APPLE:
System.out.println(57 + "kcal");
break;
case PEACH:
System.out.println(34 + "kcal");
break;
case BANANA:
System.out.println(93 + "kcal");
break;
}
}
}
enum 과 생성자
1
2
3
4
5
6
7
8
9
10
11
12
13
14
enum Fruit {
APPLE, PEACH, BANANA;
// 생성자
Fruit() {
System.out.println("Call Constructor " + this);
}
}
public class Demo {
public static void main(String[] args) {
Fruit type = Fruit.APPLE;
}
}
예제1️⃣
ButtonMode.java
1
2
3
public enum ButtonMode {
LIGHT, DARK
}
ButtonSpace.java
1
2
3
public enum ButtonSpace {
SINGLE, DOUBLE, TRIPLE
}
Button.java
1
2
3
4
5
6
7
8
9
10
11
12
public class Button {
private ButtonMode buttonMode = ButtonMode.LIGHT;
private ButtonSpace buttonSpace = ButtonSpace.SINGLE;
public void setButtonMode(ButtonMode buttonMode) {
this.buttonMode = buttonMode;
}
public void setButtonSpace(ButtonSpace buttonSpace) {
this.buttonSpace = buttonSpace;
}
}
Main.java
1
2
3
4
5
6
7
Button button1 = new Button();
button1.setButtonMode(ButtonMode.DARK);
button1.setButtonSpace(ButtonSpace.TRIPLE);
// ⚠️ 아래와 같은 오용이 방지됨
// button1.setButtonMode(ButtonSpace.DOUBLE);
예제2️⃣ (클래스 내부 작성)
Button.java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
public class Button {
enum Mode { LIGHT, DARK }
enum Space { SINGLE, DOUBLE, TRIPLE }
private Mode mode = Mode.LIGHT;
private Space space = Space.SINGLE;
public void setMode(Mode mode) {
this.mode = mode;
}
public void setSpace(Space space) {
this.space = space;
}
}
Main.java
1
2
3
4
Button button1 = new Button();
button1.setMode(Button.Mode.DARK);
button1.setSpace(Button.Space.DOUBLE);
예제3️⃣ (추가 기능)
클래스처럼 필드, 생성자, 메소드를 가질 수 있다.
YalcoChickenMenu.java
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
31
32
33
34
35
public enum YalcoChickenMenu {
FR("후라이드", 10000, 0),
YN("양념치킨", 12000, 1),
GJ("간장치킨", 12000, 0),
RS("로제치킨", 14000, 0),
PP("땡초치킨", 13000, 2),
XX("폭렬치킨", 13000, 3);
private String name;
private int price;
private int spicyLevel;
YalcoChickenMenu(String name, int price, int spicyLevel) {
this.name = name;
this.price = price;
this.spicyLevel = spicyLevel;
}
public String getName() { return name; }
public int getPrice() { return price; }
public void setPrice(int price) {
this.price = price;
}
public String getDesc () {
String peppers = "";
if (spicyLevel > 0) {
peppers = "🌶️".repeat(spicyLevel);
}
return "%s %s원 %s"
.formatted(name, price, peppers);
}
}
Main.java
1
2
3
4
5
6
7
YalcoChickenMenu menu1 = YalcoChickenMenu.YN;
YalcoChickenMenu menu2 = YalcoChickenMenu.RS;
YalcoChickenMenu menu3 = YalcoChickenMenu.XX;
String menu1Name = menu1.getName(); // 양념치킨
int menu2Price = menu2.getPrice(); // 14000
String menu3Desc = menu3.getDesc(); // 폭렬치킨 13000원 🌶️🌶️🌶️
1
2
menu2.setPrice(16000);
int menu2NewPrice = menu2.getPrice(); // 16000
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
31
// ⭐️ 열거형의 메소드들
// valueOf()
// 문자열로부터 enum 객체 반환
// 없다면 런타임 에러 발생
YalcoChickenMenu[] byNames = new YalcoChickenMenu[] {
YalcoChickenMenu.valueOf("FR"),
YalcoChickenMenu.valueOf("PP"),
YalcoChickenMenu.valueOf("GJ"),
// YalcoChickenMenu.valueOf("NN"), // ⚠️ 런타임 에러
};
// 💡 name 메소드 : 각 항목의 이름 반환
// names: ["YN", "RS", "XX"]
String[] names = new String[] {
menu1.name(), menu2.name(), menu3.name()
};
// 💡 ordinal 메소드 : 순번 반환
// orders: [1, 3, 5]
int[] orders = new int[] {
menu1.ordinal(), menu2.ordinal(), menu3.ordinal()
};
// 💡 values 메소드 : 전체 포함된 배열 반환
// YalcoChickenMenu[] 자료형
YalcoChickenMenu[] menus = YalcoChickenMenu.values();
for (YalcoChickenMenu menu : menus) {
System.out.println(menu.getDesc());
}
예제4️⃣
YalcoChicken.java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
public class YalcoChicken {
static YalcoChickenMenu[] menus = YalcoChickenMenu.values();
public void takeOrder (String menuName) {
YalcoChickenMenu ordered = null;
for (YalcoChickenMenu menu : menus) {
if (menu.getName().equals(menuName)) {
ordered = menu;
}
}
if (ordered == null) {
System.out.println("해당 메뉴가 없습니다.");
return;
}
System.out.println(
ordered.getPrice() + "원입니다."
);
}
}
Main.java
1
2
3
4
5
6
7
System.out.println("\n- - - - -\n");
YalcoChicken store1 = new YalcoChicken();
for (String menuName : "양념치킨,능이백숙,땡초치킨".split(",")) {
store1.takeOrder(menuName);
}

