열거 타입(ENUM)
상수 목록을 담을 수 있는 데이터 타입.
• 특정한 변수가 가질 수 있는 값을 제한할 수 있다. 타입-세이프티 (Type-Safety)를 보장할 수 있다. (코드의 안정성 향상)
• ENUM을 사용하면 가독성이 올라간다.( int 통해 0: 실패, 1: 성공 보다 Status.FAIL, Status.SUCCESS와 같이 의미를 담을 수 있다.)
• 싱글톤 패턴을 구현할 때 사용하기도 한다.
타입 세이프티 보장
만약 int로 다음과 같이 status를 구분한다 생각해보자
0-> 주문 실패
1-> 주문 완료
.....
int status;
....
if(status==0)//주문 실패 로직 수행
if(status==1)//주문 성공 로직 수행
status는 int 로 선언되었기에 사실상 int 범위 내 모든 값이 올 수 있다.
하지만, 실제 status에서 유효한 값은 0 or 1로, 그 외에 값이 들어온다면, 그에 대한 대처를 수행해야한다.
ENUM을 통해 status 선언시
public enum OrderStatus {
FAIL, SUCCESS;
}
ENUM 사용 시, ENUM으로 정의한 상수값(FAIL, SUCCESS) 외의 그 어떠한 값도 들어갈 수 없고, 그 외의 값이 들어오면 "컴파일 에러"로 바로 찾을 수 있다. (타입 세이프티를 컴파일 시점에서 보장한다.) 이는 매우 큰 장점이다.
싱글톤 패턴에 사용
ENUM의 각 타입들(FAIL, SUCCESS)은 각각 JVM내에서 오로지 1개만 만들어진다. 이러한 특징 때문에 싱글톤 패턴을 안전하게 쓰기 위해 ENUM을 추천하기도 한다.
ENUM 실전 활용
질문1) 특정 enum 타입이 가질 수 있는 모든 값을 순회하며 출력하라.
// OrderStatus[] values = OrderStatus.values();
Arrays.stream(OrderStatus.values()).forEach(System.out::println);
ENUM의 values() 메소드 사용 시, 해당 ENUM타입의 모든 상수 값들을 담은 Array를 반환한다.
이후 stream, 혹은 for 문을 통해 각 원소를 출력하면 된다.
질문2) enum은 자바의 클래스처럼 생성자, 메소드, 필드를 가질 수 있는가?
public enum OrderStatus {
SUCCESS(0), FAIL(1);
private int number;
OrderStatus(int number) {
this.number = number;
}
}
당연히 그렇다. ENUM은 class의 한 종류로, 값이 한정되어 있는 특수한 class라고 생각하면 된다.
질문3) enum의 값은 == 연산자로 동일성을 비교할 수 있는가?
답은 Yes다. ENUM은 JVM 내에서 1개의 인스턴스를 보장하기에, ==으로 가능하다.
equals()를 굳이 사용할 필요없다. ( equals는 Null을 가지고 있기에, NullPointException 문제가 생길 수 도 있다.)
Order order = xxxx;//여기서 order에 orderStatus가 NULL이라고 가정해보자.
if (order.orderStatus == OrderStatus.DELIVERED) { //NullPointException 발생 x
System.out.println("delivered");
}
if (order.orderStatus.equals( OrderStatus.DELIVERED)) {//NullPointException 발생
System.out.println("delivered2");
}
만약 order.orderStatus가 NULL 이라면, 같지 않다는 뜻이다. 굳이 NullPointException 예외가 터질 이유가 없다.
+@: equals() VS ==
Int 등의 기본형은 ==연산으로 값을 비교 가능하다.
하지만, String 등 기본타입 외의 타입은 == 연산 수행 시, "주소 값" 을 비교하게 된다.
이 때문에, 각각의 객체들은 각자의 equals() 메소드를 가지고 있고, 이를 오버라이드 해서 객체간의 값을 비교하는 연산을 커스텀 할 수 있는 것이다.
그 중, String 타입의 경우, 이미 적절하게 equals() 메소드가 적절하게 오버라이딩 되어있기에, equals() 메소드로 두 String 변수의 "값"이 같은지 비교할 수 있다.
String car = "benz";
String vehicle = car;
String car2 = new String("benz");
System.out.println("vehicle => " + vehicle); // benz
System.out.println("vehicle.equals(car) => " + vehicle.equals(car)); // true
System.out.println("car.equals(car2) => " + car.equals(car2)); // true
System.out.println(car == vehicle); // true
System.out.println(car == car2); // false
과제) enum을 key로 사용하는 Map을 정의하세요. 또는 enum을 담고 있는 Set을 만들어 보세요
-> 일반적인 Map, Set 혹은 HashMap, HashSet에 ENUM을 담는 것보다. EnumSet, EnumMap이 훨씬 효율적이다.
왜일까?
우선 간단하게 보자면, ENUM은 "제한이 많은" 객체이다. 그렇기에 당연히 이러한 제약 사항을 고려해서 ENUM에 최적화 된 Set, Map을 사용하면 성능이 좋을 것이다.
조금 더 자세히 보자.
1. EnumMap은 값을 찾을 때, 이늄상수가 index정보를 ordinal메소드로 제공하고 있기 때문에, 바로 찾을 수 있다.
2. 반면, HashMap은 찾을 때, key값을 hash메소드로 index로 변환하고 찾아야 한다.
3. 값을 넣을 때, EumMap은 key의 index정보로 값이 저장된 위치를 찾아서 바로 값을 넣는다.
4. 하지만, HashMap은 key값을 hash로 만들고, 배열의 크기를 조절하는 등의 일이 추가로 필요하다.
5. 때문에, 배열의 크기가 고정되고 바로 찾을 수 있는 EnumMap이 성능상 훨씬 더 효율적이다.
6: ENUM은 상수의 개수가 결정 되어 있고, null이 없다 따라서, 때문에 배열을 늘리는 작업, null을 처리하는 작업을 수행할 필요가 없다.
'java' 카테고리의 다른 글
java의 동작 원리 및 구조 [JVM의 구조] (0) | 2023.08.02 |
---|---|
[effective java] 생성자에 매개변수가 많다면 빌더를 고려하자 (0) | 2023.07.18 |
[java] 체크, 언체크 예외에 대한 분석과 잘못된 오해 (0) | 2023.07.18 |
[이펙티브 자바] 정적 팩토리 메소드 (0) | 2023.07.16 |