-
Notifications
You must be signed in to change notification settings - Fork 2
Open
Labels
🐦 06 Enums & Annotations6장 열거 타입과 애너테이션6장 열거 타입과 애너테이션
Description
🍑 서론
정수, 문자열 상수가 아닌 열거 타입(enum type)을 사용하라
-
정수 상수
- 타입 안정성을 보장할 수 없다. (namespace가 없다)
- 표현력이 좋지 않다. (문자열로 출력하기가 까다로워 의미를 알기 어렵다.)
-
문자열 상수
- 표현력은 좋지만, 문자열 값을 그대로 하드코딩(오타 발생가능성)
- 문자열 비교에 따른 성능 저하
-
열거타입
- 타 언어와 다르게 완전한 형태의 클래스
- 훨씬 추상적인 개념들도 표현가능
- 타입 안정성 보장 가능
- 타 언어와 다르게 완전한 형태의 클래스
Enum
- 상수를 표현하기 위해 사용되는 클래스의 특별한 형태(멤버변수O, 생성자O, 메서드O)
- 모든 열거형의 부모클래스
- 타입안정성과 유지보수성, 가독성 제공
- 코드가 단순해지며 가독성이 좋다.
- 인스턴스 생성, 상속을 방지하며 상수값의 타입 안전성이 보장된다.
- enum이라는 키워드로 열거형의 의도를 명확히 드러낸다.
- 다른 클래스와 마찬가지로 java파일, 클래스 안, 클래스 밖 선언 가능
- 서로 연관된 상수들의 집합
- Enum 클래스 형을 기반으로 한 클래스형 선언(모든 상수클래스의 부모클래스 = enum)
enum vs static final
- 코드에 주석이 없을 경우 코드를 이해하기 어려움
int type = 1;
if(type == 1) {
System.out.println("boy");
} else {
System.out.println("girl");
}
//type에 대한 주석이나 if문 안에서 처리하는 내용에 대한 주석이 없으면 코드를 이해하기 어렵다.
- 해결방안 > final static을 설정한다.
private final static int BOY = 1;
private final static int GIRL = 2;
public static void main(String[] args) {
int type = 1;
if(type == BOY) {
System.out.println("boy");
} else if(type == GIRL){
System.out.println("girl");
}
}
//final static으로 설정하면 주석없이도 의미를 파악할 수 있다.private final static int BOY = 1;
private final static int GIRL = 2;
private final static int MONDAY = 1;
private final static int TUESDAY = 2;
// 그러나 같은 상수명을 갖는 다른의미의 값이 존재하거나 다른 상수명이지만 같은 값을 가지는 경우가 있을 수 있고 에러가 발생할 수 있다.
// 각각의 상수들은 자신을 인스턴스화 한 값을 할당한다.
// BOY와 MONDAY는 서로 다른 데이터를 의미하는데 비교할 경우
if(BOY == MONDAY) {
...
}
//컴파일 에러가 발생하지 않고 런타임 단계에서 생각지 못한 문제를 발생시킬 수 있다.- 해결방안 > class로 작성된 상수를 인스턴스화하여 구체화 한다.
class SEX {
public final static SEX BOY = new SEX(1);
public final static SEX GIRL = new SEX(2);
int num;
public SEX(int num) {
this.num = num;
}
}
class DAY {
public final static DAY MONDAY = new DAY();
public final static DAY TUESDAY = new DAY();
}
// 인스턴스화하면 자신의 타입으로 비교하기 때문에 컴파일시 에러를 확인할 수 있다.
int type = 1;
switch (type) {
case DAY.MONDAY:
System.out.println("월요일");
break;
case DAY.TUESDAY:
System.out.println("화요일");
break;
}
//그런데 switch문에 사용할 수 없다.enum SEX {
BOY(1), GIRL(2);
private int sex;
SEX(int type) {
sex = type;
}
public int getSex() {
return sex;
}
}
enum DAY {
MONDAY, TUESDAY
}
SEX type = SEX.BOY;
switch (type) {
case BOY:
System.out.println("boy");
break;
case GIRL:
System.out.println("girl");
break;
}- enum과 static을 선언한 constant는 목적이 다르다.
- enum은 연관된 상수들을 묶어서 추상화 시킨 거고(개념의 추상화) constant는 값의 재할당을 막기 위한 목적에 맞다.
🍑 본론
- ordinal 메서드 대신 인스턴스 필드를 사용하라
- ordinal() 메서드 : 열거 타입 상수가 몇번째 위치인지 반환하는 메서드(0부터 시작)
ordinal을 잘못 사용한 예
public enum Esenmble {
//SOLO는 0, DUET은 1, ...
SOLO, DUET, TRIO, QUARTET, QUINTET,
SEXTET, SETPTET, OCTET, NONET, DECTET;
public int numberOfMusicians() {
return ordinal();
//return orinal() + 1;
}
public static void main(String[] args) {
Ensemble solo = Ensemble.SOLO;
System.out.println(solo.numberOfMusicians()); // 0 출력
}
}
//동작은 하지만 유지보수하기가 끔찍하다.문제점이 무엇이냐?
//예시1
public enum Esenmble {
//SOLO(=1명)와 DUET(=2명)의 위치를 바꾼다면?
DUET, SOLO, TRIO, QUARTET, QUINTET,
SEXTET, SETPTET, OCTET, NONET, DECTET;
//DUET이 1로 출력돼버리는 상황 발생
//순서를 바꿔서는 안된다!
}
//예시2
public enum Esenmble {
//3중 4중주(=12명으로 구성)를 추가한다면?
DUET, SOLO, TRIO, QUARTET, QUINTET,
SEXTET, SETPTET, OCTET, NONET, DECTET, TRIPLE_QUARTET;
public int numberOfMusicians() {
return orinal() + 1;
}
public static void main(String[] args) {
Ensemble triple_quartet = Ensemble.TRIPLE_QUARTET;
System.out.println(triple_quartet.numberOfMusicians()); // 11 출력
//값을 중간에 비워둬서도 안된다.
}
}
//예시3
public enum Esenmble {
//복사중주(2*4 = 8명)를 추가한다면?
DUET, SOLO, TRIO, QUARTET, QUINTET,
SEXTET, SETPTET, DOUBLE_QUARTET,
OCTET, NONET, DECTET;
//복사중주는 8로 출력되지만 그 뒤에것들은 1씩 값이 밀려나서
//의도된 것과 다르게 numberOfMusicians 메서드가 작동
}해결책은?
- 해결책 : ordinal 메서드를 사용하지말고, 인스턴스 필드를 추가하여 거기에 저장!
public enum Ensemble {
//위의 문제점(순서 변경, 중간값 비워짐, 값 중복)이 모두 해결
DUET(2), SOLO(1), TRIO(3), QUARTET(4), QUINTET(5),
SEXTET(6), SETPTET(7), DOUBLE_QUARTET(8),OCTET(8), NONET(9), DECTET(10), TRIPLE_QUARTET(12);
private final int numberOfMusicians; //각 앙상블 타입을 구성하는 뮤지션들의 숫자를 필드변수로 추가
Ensemble(int size) { this.numberOfMusicians = size } // 각 타입에 뮤지션들의 숫자를 넣도록 강제
//ordinal() 메서드를 사용하지 않고, 인스턴스 필드를 이용
public int numberOfMusicians() {
return numberOfMusicians
}
}그럼 ordinal() 메서드는 왜 만들어놓은걸까?
- Enum에 정의된 상수들은 순서와 개수가 불변이다! => 배열과 찰떡궁합
import java.util.EnumMap;
public class test03 {
public enum Day {
SUNDAY, MONDAY, TUESDAY, WEDNESDAY, THURSDAY, FRIDAY, SATURDAY;
}
public static void main(String[] args) {
//EnumMap : Enum을 키로 갖는 Map의 일종
//Enum의 각 상수들은 고유한 순서를 가지고,
//그 순서와 개수가 불변이므로
//이를 바탕으로 EnumMap을 내부적으로 배열을 이용하여 구현
EnumMap<Day, String> schedule = new EnumMap<>(Day.class);
// 일정을 추가할 때 ordinal() 메서드를 사용하여 순서를 기반으로 일정을 추가
schedule.put(Day.MONDAY, "Network Study");
schedule.put(Day.TUESDAY, "LOSTARK");
schedule.put(Day.WEDNESDAY, "SSAFY PROJECT");
// Enum클래스의 values 메서드는 정의된 모든 상수를 배열로 반환(이때 ordinal메서드 이용)
// 요일을 출력할 때 ordinal() 메서드를 사용하여 순서를 표현
for (Day day : Day.values()) {
String event = schedule.get(day);
if (event != null) {
System.out.println(day + ": " + event);
}
}
}
}- EnumMap의 구현 참고
🍑 결론
- referenced by
Reactions are currently unavailable
Metadata
Metadata
Assignees
Labels
🐦 06 Enums & Annotations6장 열거 타입과 애너테이션6장 열거 타입과 애너테이션