목표
자바의 열거형에 대해 학습하세요.
학습할 것 (필수)
- enum 정의하는 방법
- enum이 제공하는 메소드 (values()와 valueOf())
- java.lang.Enum
- EnumSet
왜 사용하는가 ?
열거 타입(enum)이란 상수값을 정의한 다음 그외의 값은 허용하지 않는 타입이다.
자바 1.5 이전 열거 타입(enum)이 존재하지 않았을때 다음 코드처럼 사용했었다.
public class CARD {
public static final int SAMSUNG = 0;
public static final int KAKAO =1;
public static final int HYUNDAI =2;
}
다음과 같은 사용은 정수 열거 패턴(int enum pattern) 이라고 부르는데
해당 패턴은 타입의 안전을 보장할 수 없고 표현력도 좋지않다.
또한 해당 값을 디버거로 출력했을때 단지 숫자로만 보여서 해당하는 숫자가 무엇을 의미하는지 프로그래머는 파악하기 힘들다.
그러면 문자열 열거 패턴(string enum pattern) 을 사용하면 되는 것이 아닌가?
라는 의문이 들 수 있지만 정수 열거 패턴보다 더욱 안좋다.
왜냐하면
값이 string 이면 해당 타입을 가져다가 쓰는 클라이언트 측 코드에서는 하드코딩을 할 수 밖에없다.
이러한 문제점은 선언한 문자열 값을 잘못 입력해도 컴파일 시점에 잡을 수 없는 문제가 발생한다.
이러한 문제점 때문에 자바에서는 enum type 생기게 된 것이다.
effective java 3판 Item34 에 자세한 설명이 있습니다.
enum 정의하는 방법
public enum CARD {
SAMSUN,KAKAO,HYUNDAI
}
enum 을 정의하는 방법은 다음과 같이 매우쉽다.
하지만 enum 이 가지고 있는 특성들을 이해하는 것이 더욱 중요하다.
특성
- enum 타입은 완전한 클래스다. -> 상수하나당 인스턴스를 생성하여 public static final 필드 로 공개함.
- 밖에서 접근할 수 있는 생성자가 없다 - > 생성자 접근지정자가 private 이다.(singleton 보증)
- 완전한 클래스임으로 data와 method를 가질 수 있다.
- 단 Enum 클래스를 상속 받고있음으로 다른 클래스를 상속받을수 없다 ( 자바는 다중상속 불가 )
다음과 같은 특성 덕분에 Enum 타입은 이러한 코드를 작성 할 수 있다.
public enum CARD {
SAMSUNG("삼성카드",money->(money/100)), //CARD.SAMSUNG 으로 접근가능함(public static final 필드)
KAKAO("카카오카드",money->(money*2/100)),
HYUNDAI("현대카드",money->(money*3/100));
private final String name; //data를 가질수있다.
private final Function<Long,Long> point;
CARD(String name,Function<Long,Long> point) { //해당 생성자는 private 입니다 생략되어있음
this.name = name;
this.point=point;
}
public String getName() {
return name;
}
public Long payBack(Long money){ //method를 가질수 있다
return point.apply(money);
}
}
Main 코드
public static void main(String[] args) {
CARD[] cards = CARD.values();
Long money =1000L;
for (CARD card : cards) {
System.out.printf("%d원을 결제 할때 %s의 적립금은 %d원 \n"
,money,card.getName(),card.payBack(money));
}
}
결과
enum이 제공하는 메소드 (values()와 valueOf())
valueof(String name)
valueof(Class<T> enumtype,String name)
valueOf() 은 Enum 타입에 지정된 이름중 지정된 상수를 반환한다.
-> 이 메서드는 지정된 이름과 정확히 일치해야 오류가 발생하지 않는다.
사용 방법은 다음과 같다.
public class MainClient {
public static void main(String[] args) {
CARD samsung1 = Enum.valueOf(CARD.class,"SAMSUNG");
CARD samsung = CARD.valueOf("SAMSUNG");
System.out.println(samsung1== samsung);
}
}
values()
-> 모든 요소들을 배열로 반환 합니다.
public class MainClient {
public static void main(String[] args) {
CARD[] cards = CARD.values();
for (CARD card : cards) {
System.out.printlne(card.name())
}
}
}
valueof(Class<T> enumtype,String name) 는 enum 클래스에 정의되어있는데...
valueof(name) ,values() 메서드들은 어디에 정의되어 있는건가 ?
-> 해당 메서드들은 컴파일러에 의해서 정의된다고한다.
자세한 내용은: docs.oracle.com/javase/specs/jls/se7/html/jls-8.html#jls-8.9.2
java.lang.Enum
모든 enum 은 해당 클래스를 상속받고있으며
Enum.class 의 메서드들은 다음과 같다.
근데 여기서 자주 쓰는건 name() , equals() 말고는 잘안쓰는 것 같다.
EnumSet
Set 자료구조를 구현하고 있음으로 Set 가지고 있는 특성을 그대로 가지고있다.
말그대로 열거타입의 set 자료구조 이며
열거타입에 set 자료구조가 필요할때 HashSet 보다 성능이 훨씬 좋음으로 해당 자료구조를 이용하자
EnumSet보다 HashSet이 성능이 좋은이유는 enum은 단일 객체임을 보장 함으로 해싱작업을 하지 않기 때문이다.
사용법
public class MainClient {
public static void main(String[] args) {
EnumSet<CARD> cards1 = EnumSet.allOf(CARD.class); //전부 가져오기
System.out.println(cards1);
EnumSet<CARD> cards2 = EnumSet.of(CARD.HYUNDAI, CARD.KAKAO); // 선택 가져오기
System.out.println(cards2);
EnumSet<CARD> cards3 = EnumSet.complementOf(cards2); //선택한거 제외하고 가져오기
System.out.println(cards3);
EnumSet<CARD> cards4 = EnumSet.range(CARD.SAMSUNG, CARD.HYUNDAI); //범위로 가져오기
System.out.println(cards4);
}
}
결과
'Java > live-study' 카테고리의 다른 글
백기선라이브스터디 13주차 : I/O (0) | 2021.02.17 |
---|---|
[Java] 백기선 라이브스터디 12주차: 애노테이션 (0) | 2021.02.03 |
[Java]백기선 라이브 스터디 10주차 과제: 멀티쓰레드 프로그래밍 (0) | 2021.01.20 |
[Java] 백기선 라이브스터디 9주차 : 예외 처리 (0) | 2021.01.14 |
[JAVA] 백기선 라이브스터디 8주차 과제: 인터페이스 (0) | 2021.01.06 |