Search
Duplicate
📒

[Java Study] 06. ENUM(열거 타입)

상태
완료
수업
Java Study
주제
Util
4 more properties
참고

열거 타입(Enum)

NOTE
자바에서 Enum을 지원하기 이전에는 상수값들을 표현하기 위해 정수 열거 패턴이나 문자열 열거 패턴을 사용했습니다. 이런 방식은 여러 문제를 유발할 수 있습니다.
public class Fruit { public static final int APPLE_FUJI = 0; public static final int APPLE_PIPPIN = 1; public static final int APPLE_GRANNY_SMITH = 2; public static final int ORANGE_NAVEL = 0; public static final int ORANGE_TEMPLE = 1; public static final int ORANGE_BLOOD = 2; }
Java
복사
정수 열거 패턴
public class StringGrade { public static final String BASIC = "BASIC"; public static final String GOLD = "GOLD"; public static final String DIAMOND = "DIAMOND"; }
Java
복사
문자열 열거 패턴
기본타입의 String이나 Int로 상태나 카테고리를 표현하면 잘못된 값을 입력할 가능성이 있으며, 타입 안전성을 보장할 수 없습니다.
자바는 열거 패턴의 단점을 없애고, 클래스의 장점을 가져오는 열거 타입을 제시했습니다.

Enum 참조방식

NOTE
Enum은 열거, 목록, 알람표라는 뜻을 가지고 있으며 요소, 멤버라 불리는 명명된 값의 집합을 이루는 자료형입니다. (상수 데이터 집합)
enum Week { MONDAY, TUESDAY, WEDNESDAY, THURSDAY, FRIDAY, SATURDAY, SUNDAY }
Java
복사
enum 객체
public class Week { public static final Week MONDAY = new Week(); public static final Week TUESDAY = new Week(); public static final Week WEDNESDAY = new Week(); public static final Week THURSDAY = new Week(); public static final Week FRIDAY = new Week(); public static final Week SATURDAY = new Week(); public static final Week SUNDAY = new Week(); private Week() {} // 외부에서 생성자 호출 막음 }
Java
복사
class 형태
열거 타입 자체는 클래스이며, 상수 하나당 자신의 인스턴스를 하나씩 만들어 public static final필드로 공개합니다.
열거 타입은 밖에서 접근할 수 있는 생성자를 제공하지 않으므로, 사실상 final입니다.
즉, 클라이언트가 인스턴스를 직접 생성/확장 할 수 없으므로 싱글톤이 유지됩니다.
열거타입에는 임의의 메서드나 필드를 추가할 수 있고, 임의의 인터페이스를 구현하게 할 수도 있습니다.
// 열거타입 변수 = 열거타입.열거상수; Week monday = Week.MONDAY; Week sunday = Week.SUNDAY; Week today = null; // 참조 타입이기 때문에 null도 저장 가능 today = Week.SUNDAY; System.out.println(today == Week.SUNDAY); // true(주소비교)
Java
복사
Enum의 상수들은 reference타입으로 분류되어 heap 메모리에 저장됩니다.
Stack 영역(지역변수)에 주소값을 저장하며, Week.SUNDAY를 비교하면 같은 주소이기 때문에 true 결과값이 출력됩니다.
Enum 메모리

ENUM의 장점

코드가 간결해지고 가독성이 향상됩니다.
허용 가능한 값들을 제한함으로써 유형 안전성을 제공합니다.
자체 클래스 상수와 달리 switch문에서 사용할 수 있습니다.
enum은 본질적으로 Thread safe인 싱글톤 객체이므로, 싱글톤 클래스를 생성하는 데 사용됩니다.

Enum 메소드 종류(name(), ordinal(), compareTo(), valeus())

NOTE
String과 같이 여러 클래스가 자체 내장 메소드를 가지고 있듯이, enum역시 내장 메소드를 지니고 있습니다!
enum Week { MONDAY, TUESDAY, WEDNESDAY, THURSDAY, FRIDAY, SATURDAY, SUNDAY }
Java
복사
enum 객체
// name(): 객체 문자열 // ordinal(): 순서 리턴 Week w = Week.FRIDAY; System.out.println(w.name()); // FRIDAY(상수이름) System.out.println(w.ordinal()); // 4(순서) // compareTo(): 객체 비교 Week w1 = Week.TUESDAY; // 2(순서) Week w2 = Week.SATURDAY; // 6(순서) System.out.println(w1.compareTo(w2)); // -4 System.out.println(w2.compareTo(w1)); // 4 // valueOf(): 주어진 이름과 일치하는 상수 반환 Week w3 = Week.valueOf("SUNDAY"); // 문자열과 맞는 열거객체 반환 System.out.println(w3); // SUNDAY // values(): 모든 Enum 객체를 배열로 담아서 반환 for (Week value : Week.values()) { // 모든 열거객체 배열반환 System.out.println(value); // MONDAY ~ SUNDAY }
Java
복사

 ordianl() 대신 인스턴스 필드 권장

ordinal()을 사용하게되는 경우 상수 선언 순서를 바꾸거나 추가하는경우 각 상수의 ordinal()의 출력값이 바뀌어서 유지보수하기 어려워진다.
public enum Esemble { SOLO(1), DUET(2), TRIO(3), QUARTET(4), QUINTET(5), SEXTET(6), SEPTET(7), OCTET(8), DOUBLE_QUARTET(8), NONET(9), DECTET(10), TRIPLE_QUARTET(12); private final int numberOfMusicians; Esemble(int size) { this.numberOfMusicians = size; } public int numberOfMusicians() { return numberOfMusicians; } }
Java
복사
인스턴스 필드 방식
열거 타입 상수에 열견된 값은 ordinal() 대신 인스턴스 필드에 저장하자.

ENUM을 사용하는 방법

NOTE
public enum HttpStatus { OK(200, "OK"), BAD_REQUEST(400, "Bad Request"), NOT_FOUND(404, "Not Found"), INTERNAL_SERVER_ERROR(500, "Internal Server Error"); // 필드값 private final int code; private final String message; // 생성자 HttpStatus(int code, String message) { this.code = code; this.message = message; } // 코드관련 함수 public static HttpStatus findByCode(int code) { for (HttpStatus status : values()) { if (status.getCode() == code) { return status; } } return null; } public int getCode() { return code; } public String getMessage() { return message; } public boolean isSuccess() { return code >= 200 && code <= 299; } }
Java
복사
자바 열거타입 예제 - HTTP Status
public static void main(String[] args) { int httpCodeInput = 200; HttpStatus status = HttpStatus.findByCode(httpCodeInput); if (status == null) { System.out.println("정의되지 않은 코드"); } else { System.out.println(status.getCode() + " " + status.getMessage()); System.out.println("isSuccess = " + status.isSuccess()); } }
Java
복사
사용코드
public enum PayrollDaySt { MONDAY(PayType.WEEKDAY), TUESDAY(PayType.WEEKDAY), WEDNESDAY(PayType.WEEKDAY), THURSDAY(PayType.WEEKDAY), FRIDAY(PayType.WEEKDAY), SATURDAY(PayType.WEEKEND), SUNDAY(PayType.WEEKEND); private final PayType payType; PayrollDaySt(PayType payType) { this.payType = payType; } int pay(int minutesWorked, int payRate){ return payType.pay(minutesWorked, payRate); } enum PayType { WEEKDAY { int overtimePay(int minsWorked, int payRate){ return minsWorked <= MINS_PER_SHIFT ? 0 : (minsWorked - MINS_PER_SHIFT) * payRate / 2; } }, WEEKEND { int overtimePay(int minsWorked, int payRate){ return minsWorked * payRate / 2; } }; abstract int overtimePay(int mins, int payRate); private static final int MINS_PER_SHIFT = 8 * 60; int pay(int minsWorked, int payRate){ int basePay = minsWorked * payRate; return basePay + overtimePay(minsWorked, payRate); } } }
Java
복사
전략 Enum 패턴
enum SingletonEnum { INSTANCE; private final Client dbClient; SingletonEnum() { dbClient = Database.getClient(); } public static SingletonEnum getInstance() { return INSTANCE; } public Client getClient() { return dbClient; } }
Java
복사
Enum 싱글톤 패턴
public class Main { public static void main(String[] args) { SingletonEnum singleton = SingletonEnum.getInstance(); singleton.getClient(); } }
Java
복사
사용 코드

EnumSet

NOTE
EnumSet은 enum타입의 요소들만을 포함하는 set구현체 이며 내부적으로 비트벡터를 사용하여 enum 상수들을의 집합을 효율적으로 표현합니다!
EnumSetenum 타입의 요소들을 다룰 때 매우 빠른 성능을 제공합니다.
일반적인 set구현 보다 메모리 사용량이 적고, 처리속도가 빠릅니다.
enum 상수의 집합을 효율적으로 관리하고자 할 때 주로 사용됩니다.
enum 상수의 그룹을 빈번하게 CRUD하는 연산이 필요할때 매우 효과적입니다.
public static void main(String[] args) { // 모든 요일을 포함하는 EnumSet 생성 EnumSet<Week> week = EnumSet.allOf(Week.class); // 주말만 포함하는 EnumSet 생성 EnumSet<Week> weekend = EnumSet.of(Week.SATURDAY, Week.SUNDAY); System.out.println("Week days: " + week); // Week days: [MONDAY, TUESDAY, WEDNESDAY, THURSDAY, FRIDAY, SATURDAY, SUNDAY] System.out.println("Weekend days: " + weekend); // Weekend days: [SATURDAY, SUNDAY] }
Java
복사
EnumSet 예제코드

EnumMap

NOTE
EnumMap은 키로 enum 타입의 요소들만 사용하는 map 구현체이며, 내부적으로 배열을 사용해 enum키 엔트리를 저장하므로, enum을 사용하는 경우 매우 효율적입니다!
EnumMapenum을 키로 사용할 때 해시 기반의 맵 구현보다 더 빠른 시간과 낮은 메모리 사용량을 제공합니다.
enum은 자연스러운 순서를 이용하여 데이터를 저장하고 접근할 수 있습니다.
enum 상수를 키로 하여 데이터를 매핑해야 하는경우 효과적으로 관리할 수 있습니다.
public static void main(String[] args) { // Day 열거 타입을 키로 하고 String을 값으로 하는 EnumMap 생성 EnumMap<Week, String> weekMap = new EnumMap<>(Week.class); // 각 요일에 대한 활동을 맵에 추가 weekMap.put(Week.MONDAY, "Study Java"); weekMap.put(Week.TUESDAY, "Work on project"); weekMap.put(Week.WEDNESDAY, "Attend seminar"); weekMap.put(Week.THURSDAY, "Write blog post"); weekMap.put(Week.FRIDAY, "Review code"); weekMap.put(Week.SATURDAY, "Relax"); weekMap.put(Week.SUNDAY, "Plan for next week"); // 모든 요일과 해당 활동 출력 for (Week day : Week.values()) { System.out.println(week + ": " + weekMap.get(day)); } }
Java
복사
EnumMap 예제코드

Enum 리플렉션(동적처리)

NOTE
Enum은 그 자체로 특별한 클래스 이기 때문에, Class객체를 통해서 Enum을 다룰 수 있습니다.
public enum Fruit { APPLE("Apple", 1), BANANA("Banana", 2), CHERRY("Cherry", 3); private final String name; private final int id; Fruit(String name, int id) { this.name = name; this.id = id; } public String getName() { return name; } public int getId() { return id; } }
Java
복사
public class EnumUtils { // 주어진 Enum 타입과 ID를 사용하여 상수반환 public static <T extends Enum<T>> T getEnumConstantById(Class<T> enumType, int id) { // EnumType이 enum인가? if (!enumType.isEnum()) { throw new IllegalArgumentException("The provided class must be an enum type."); } // getEnumConstants: Enum의 모든 상수를 배열로 얻는다. for (T enumConstant : enumType.getEnumConstants()) { if (((Fruit) enumConstant).getId() == id) { return enumConstant; } } throw new IllegalArgumentException("No enum constant with id " + id + " in " + enumType); } public static void main(String[] args) { Class<Fruit> fruitClass = Fruit.class; // 모든 enum 상수 출력하기 for (Fruit fruit : fruitClass.getEnumConstants()) { System.out.println(fruit.getName() + " has id " + fruit.getId()); } // ID로 enum 상수 찾기 Fruit fruit = getEnumConstantById(fruitClass, 2); System.out.println("Fruit with ID 2 is " + fruit.getName()); } }
Java
복사
Enum을 동적으로 관리하기 위한 메서드
Apple has id 1 Banana has id 2 Cherry has id 3 Fruit with ID 2 is Banana
Java
복사
결과 코드