java - enum

Development/Java 2012. 11. 5. 13:34


Java의 enum class는 enumeration 즉, '열거형 타입'을 의미하는 특수한 클래스 입니다. 개발에 필요한 열거형 상수들을 적절히 모아서 조금더 객체지향적으로 사용할 수 있는 고급 기술(?)이고, 소스코드에서 하드코딩 요소를 제거하는데 큰 도움이 됩니다.

Java enum 사용법 1 - 기본 형태
원소들간의 구분은 콤마(,)로 합니다. 그리고 enum 객체 역시 클래스이기 때문에 기본생성자가 있어야합니다. 물론, 아래와 같은 경우에는 생성자를 생략해도 Java가 디폴트 생성자를 만들어줍니다.

1
2
3
4
5
6
public enum FontStyle {
    NORMAL, BOLD, ITALIC, UNDERLINE;
 
    FontStyle() {
    }
}

더 간단하게 인라인 클래스로 배열 선언하듯 사용할 수 있습니다. public으로 설정되어 있기 때문에 SampleClass의 인스턴스를 sample이라고 할 때 sample.FontStyle.NORMAL 처럼 접근할 수 있습니다.
1
2
3
4
public enum SampleClass {
    public enum FontStyle { NORMAL, BOLD, ITALIC, UNDERLINE }
    ...
}


Java enum 사용법 2 - 추가 속성을 부여한 형태
아래는 enum 클래스의 각 원소에 별도 설명을 부여한 형태입니다. 사람이 이해하기 좋은 추가 속성을 지정했습니다. 각 원소 뒤에 괄호를 열고 primitive 속성으로 값을 지정하면 되고, 한개 이상의 경우 콤마로 구분하면됩니다. 단, 이경우에는 설명을 저자할 수 있는 필드가 하나 추가되고 생성자가 이 필드에 값을 설정할 수 있도록 인자가 있습니다.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
public enum FontStyle {<br />
    NORMAL("This font has normal style."),
    BOLD("This font has bold style."),
    ITALIC("This font has italic style."),
    UNDERLINE("This font has underline style.");
 
    // 원소 설명
    private String description;
 
    FontStyle(String description) {
        this.description = description;
    }
    public String getDescription() {
        return this.description;
    }
}


Java enum 사용법 3 - 에러코드/에러설명을 정의한 사례
단순히 에러코드만 반환하는 환경이 아니라 사용자 친숙한 코드/설명 쌍으로 결과를 반환하는경우 또는 로깅을 조금더 보기 좋게 하는 경우 사용법2를 응용해서 속성이 2개인 원소들로 구성된 enum을 만들 수 있습니다.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
public enum Errors {
    CLIENT_ERROR("ERR_1001""This is client error."),
    IO_ERROR("ERR_1002""This is In/Out error."),
    PARSE_ERROR("ERR_1003""This is parse error."),
    CONTEXT_ERROR("ERR_1004""This is context error.");
 
    private String code;
    private String desc;
 
    Errors(String code, String desc) {
        this.code = code;
        this.desc = desc;
    }
    public String getCode() {
        return this.code;
    }
    public String getDesc() {
        return this.desc;
    }
}

실제로 사용할 때는 그때 그때 다르지만 MYException으로 래핑하기 위해 아래와 같이 throw new를 이용하고 MYException 객체는 인자로 enum 클래스를 받게 했습니다.
1
2
3
4
5
6
7
...
try {
    ...
}
catch (XXException e) {
    throw new MYException(Errors.CLIENT_ERROR);
}


Java enum을 사용하지 않는 경우
enum을 사용하지 않고 위의 폰트 스타일 예를 분기하는 경우, 가장 쉽운 방법은 아래와 같을 겁니다.
1
2
3
if ("NORMAL".equals(fontStyle)) {
    ...
}

이걸 조금 더 구조화해서 개발을 한다면 아래와 같이 별도의 static 클래스를 만들고 int 값으로 비교를 하는 것도 좋은 방법이 되겠죠. 실제로 가장 일반적인 방법이기도 하고요. SWT에서도 UI위젯의 style 속성 정의를 이런 식으로 합니다.
1
2
3
4
5
6
7
8
9
10
class FontStyle {
    public static final int NORMAL = 0;
    public static final int BOLD = 1;
    public static final int ITALIC = 2;
    public static final int UNDERLINE = 3;
}
 
if (fontStyle == FontStyle.NORMAL) {
    ...
}



기존 방법의 문제점
enum은 아래와 같은 문제점들을 해결하기 위해 만들어졌다고 합니다.
  • 형검사를 하지 않으므로 오류발생 소지가 있다.
  • 네임스페이스를 따르지 않으므로 중복의 소지가 있다.
  • 순서 변경, 새로운 원소 추가에 취약합니다.
  • 알아보기가 어렵습니다.

제가 생각하는 enum의 가장 큰 장점은 소스코드 속에서 사용자가 직접 입력한 String을 제거할 수 있다는 것과, 자동 형 검사를 통해 오류를 줄일 수 있다는데 있는것 같습니다. 게다가 enum 클래스는 Java VM 1.5에서 지원하지 시작한 기능으로 아무 추가 작업없이 그냥 쓸 수 있죠.

C로 개발을 할 때도 코드에서 사용할 데이터 구조체와 상수값을 별도의 헤더파일로 뽑아내어 소스코드의 하드코딩 요소들을 제거 했었습니다. enum 클래스 헤더파일을 별도의 클래스로 분리한 겁니다. 형검사라는 강력한 기능이 추가되어서 말이죠.


TODO 다음 번에는 iBatis에서 enum 지원 방법에 대해 작성을 해보려고 합니다.




참고자료
http://download.oracle.com/javase/1.5.0/docs/guide/language/enums.html


출처 - http://powerhan.tistory.com/140






java enum 정리 1 - 기본 개념

enum에 대해서 총 3부작으로 연재를 할려고 합니다.

1 - 기본 개념
2 - enum의 메쏘드
3 - java.lang.Enum 클래스와 enum의 실체

이 글은 그 첫번째로 enum에 대한 개념을 잡는 글입니다.

enum은 비스무레한 원소들이 상수로 정의되는 클래스를 대신하기 위한 것입니다. java 1.5에서 추가되었죠.
Gender를 정의하려면 enum을 사용하지 않으면 다음과 같은 class로 정의할 수 있습니다.

public class Gender{
    public static final int MALE = 1;
    public static final int FEMALE = 2;
}

위와 같은 방법이 가지는 문제점이 몇 가지 있습니다. 
첫째, MALE은 무조건 1이지만, 1이라는 숫자가 MALE만 나타내는 것은 아닙니다. 
둘째, 이 Gender의 값들을 받아서 쓰는 메쏘드에서는 1,2 이외의 숫자가 들어오면 어떤 식으로 처리를 해 주어야 할지 난감합니다.

이런 경우 Gender은 다음과 같은 enum으로 정의하면 됩니다.

public enum Gender {
    MALE, FEMALE 
}

이제 Gender를 인자로 받아서 어떤 성별이 들어왔는지 찍어주는 메쏘드를 만들어봅시다.

public class GenderTest {
    public static void printGender (Gender d){
        System.out.println(d);
    }
    public static void main(String[] args) {
        printGender(Gender.MALE);
    }
}

enum은 swtich - case에서도 사용할 수 있습니다. 이번에는 남자면 "싫어", 여자면 "좋아"를 출력해주는 메쏘드를 만들어봅시다.

public class GenderTest {
    public static void printGender(Gender d){
        System.out.println(d);
    }
    public static void print(Gender d){
        switch (d) {
        case MALE: System.out.println("싫어");break;
        default:        System.out.println("좋아");break;
        }
    }
    public static void main(String[] args) {
        printGender(Gender.MALE);
        print(Gender.MALE);
        print(Gender.FEMALE);
    }
}


여기서 유의할 점은 case MALE: 부분입니다. case Gender.MALE이 아니고 그냥 MALE입니다. switch 에 enum이 들어올 경우 컴파일러가 알아서 case 쪽에는 그 enum의 타입을 적용해 줍니다.

Gender에 어떤 요소들이 들어가 있는 지 살펴볼 수 있는 방법을 소개하죠.

for(Gender g : Gender.values()){
    System.out.println(g);
}

Gender.values() 메쏘드를 호출하면 그 enum에 들어가 있는 모든 요소들이 Gender[] 로 리턴 됩니다.


출처 - http://iilii.egloos.com/4343065/



java enum 정리 2 - enum의 메쏘드

모든 예제는 지난 글에서 썼던 Gender를 그대로 사용합니다. 코드는 아래와 같습니다.

public enum Gender {
    MALE, FEMALE
}

Static Methods

기본으로 정의되는 static method는 모두 3가집니다.

1. valueOf(String arg)

String 으로 넘긴 값을 기준으로 enum의 원소를 가져 옵니다. 즉, Gender.MALE 과 Gender.valueOf("MALE")은 같습니다.


2. valueOf(Class<T> class, String arg)

클래스를 넘겨서 받습니다. 즉, Gender.MALE 와 Gender.valueOf(Gender.class, "MALE"); 는 같습니다. 사실 valueOf(String arg)는 내부적으로 이 메쏘드를 호출합니다.


3. values()

이건 지난 시간에 설명한 그대로 enum의 요소들을 enum 타입의 배열로 리턴합니다. Gender.values() 는 
new Gender[]{Gender.MALE, Gender.FEMALE} 와 같은 값을 가집니다.



Static이 아닌 Method


1. name()
호출된 값의 이름을 리턴합니다. 
Gender.MALE.name() 은 "MALE" 이라는 String 값을 가져옵니다.

2. ordinal()
정의된 순서를 리턴합니다. 0부터 시작합니다.
즉, Gender.MALE.ordinal() 은 0을 Gender.FEMALE.ordinal()은 1을 리턴합니다.

3. compareTo(E o)
E는 자기 자신입니다. 예제로 쓴 Gender의 경우는 Gender가 될 겁니다.
이는 ordinal()을 호출해서 비교합니다. 요소들 간에 어떤 순서가 있을 때 쓰면 됩니다.(요일이 좋은 예가 되겠습니다.)
모든 enum은 Comparable을 구현하고 있습니다. Comparable 인터페이스에는 정의된 compareTo 메쏘드를 구현한 것입니다. 더 자세한 것은 다음 글에서 다루겠습니다.

기타 다른 메쏘드들은 java.lang.Object에 정의된 메쏘드들이거나 java.lang.Class에서 따온 메쏘드들이므로 설명하지 않겠습니다.


enum의 확장

Gender 별로 웃음 소리를 저장하려고 합니다. Gender를 다음과 같이 변경시킵니다.

public enum Gender {
    MALE("하하")
    , FEMALE ("호호");
    
    private String sound;
    Gender(String arg){
        this.sound = arg;
    }
    String getSound(){
        return sound;
    }

}

일반적인 class의 생성자나 메쏘드를 만들 듯이 만들면 됩니다.
위의 코드의 경우 Gender.MALE.getSound()는 "하하"를 리턴합니다.


출처 - http://iilii.egloos.com/4345025



java enum 정리 3 - java.lang.Enum 클래스와 enum의 실체

enum에 대한 마지막 글입니다.

지금까지 사용해온 예제 파일 Gender.java 는 다음과 같습니다.

public enum Gender {
    MALE, FEMALE ;
}

이것을 decompile 툴을 이용해서 decomplie해보면 다음과 같은 코드가 나옵니다.

public final class Gender extends Enum{

    private Gender(String s, int i){
        super(s, i);
    }

    public static Gender[] values(){
        Gender agender[];
        int i;
        Gender agender1[];
        System.arraycopy(agender = ENUM$VALUES, 0, agender1 = new Gender[i = agender.length], 0, i);
        return agender1;
    }

    public static Gender valueOf(String s){
        return (Gender)Enum.valueOf(enumtest/Gender, s);
    }

    public static final Gender MALE;
    public static final Gender FEMALE;
    private static final Gender ENUM$VALUES[];

    static {
        MALE = new Gender("MALE", 0);
        FEMALE = new Gender("FEMALE", 1);
        ENUM$VALUES = (new Gender[] {
            MALE, FEMALE 
        });
    }
}

이 코드는 컴파일은 되지 않습니다. java가 내부적으로 처리를 하는 것입니다. 

일단 눈 여겨 보실 부분은 values(), valueOf() 메쏘드입니다. 자바가 컴파일시에 내부적으로 만들어내는 메쏘들입니다. 그 외에 지난 시간에 말씀드린 메쏘드들은 모두 java.lang.Enum 클래스에 정의되어 있습니다.

또 한가지는 우리가 사용하는 MALE이나 FEMALE과 같은 static 멤버 변수들은 전부 public static final로 정의됩니다. 일반적인 상수처럼 정의해버립니다. 그리고 그 리스트 전부를 ENUM$VALUES라는 변수에 배열로 저장하고 있습니다.



java.lang.Enum 클래스를 열어보면 다음과 같은 클래스 선언부를 가지고 있습니다.

public abstract class Enum<E extends Enum<E>>
        implements Comparable<E>, Serializable

enum이 compareTo 메쏘드가 있는 것은 상위 클래스인 Enum에서 Comparable을 구현했기 때문입니다. 또, Serializable을 구현해서 자유롭게 저장할 수 있습니다.

Enum에 정의된 몇 가지 메쏘드들을 살펴보겠습니다.

public final boolean equals(Object other) { 
    return this==other;
}

멤버 변수같은 거 비교할 필요없습니다. 그냥 자기자신인지를 비교하고 넘어갑니다. Object에 정의되어있는 것과 별로 다르지 않습니다만 final로 선언을 해버렸습니다.


protected final Object clone() throws CloneNotSupportedException {
 throw new CloneNotSupportedException();
}

clone은 지원하지 않습니다. final로 정의해서 어떤 enum도 clone을 지원하지 않도록 만들었습니다. reflection을 쓰더라도 clone을 못하게 막았습니다. enum의 경우는 singleton처럼 사용할 수 있도록 보장해주기 위한 것입니다.
clone을 지원하게 되면 Gender.MALE.equals(Gender.MALE.clone()) 은 true를 리턴해야겠지요. 그러나 위에서 본 바와 같이 equals는 인스턴스의 값을 비교하지 않습니다. 따라서 clone을 지원한다면 equals의 구현도 바뀌어야합니다.


출처 - http://iilii.egloos.com/4346098



java enum - 보충

본 내용은 parleys.com 에 있는 Joshua bloch의 Effective java reload 동영상을 바탕으로 쓴 글입니다.

eunm에 대한 기본 지식이 없다면 이전에 정리해 놓은 글들을 먼저 보시고 보시는 게 좋을 듯합니다.

1. ordinal

enum에는 ordinal() 메쏘드가 있는데, 이 것은 각 element의 순서대로 번호가 생깁니다. 따라서 몇 번째 놈인지를 알아낼 수 있는데, 일반적으로는 사용하지 않는 것이 좋다고 합니다. ordinal의 기본 용도는 jdk 안에 있는 EnumSet이나 EnumMap 등의 성능을 위해 있는 것이지 사용자를 위해 제공하는 것이 아니라고 합니다. 만약 순서가 필요할 경우 final int 로 저장을 하라고 합니다.
ex> 
--- 틀린 예
public enum Day{ SUN, MON,....}
--- 옳은 예
public enum Day{ 
    SUN(1), MON(2), ... ;
    private final int seq;
    public Day(int seq){this.seq = seq}
    public int getSequence(){ return seq; }
}

2. enum을 이용한 singleton

singleton 패턴이 많이 쓰이기는 하지만 몇 가지 보안상 취약한 부분들이 있답니다. (특히 serialize 관련된 부분, 개인적으로 java의 Serialize는 저주라고 생각합니다!) 또, 만들기도 구찮은 부분이 있습니다. (private constructor 등)
ex>
--- class를 이용한 singleton -- Serializable의 저주가 함께하는 클래스!
public class Singleton implements Serializable{
    public static final Singleton INSTANCE = new Singleton();
    private Singleton() {}
    .. 기타 멤버 변수와 각종 메쏘드들.
}
--- enum을 이용한 singleton
public enum Singleton{
    INSTANCE;
    .. 기타 멤버 변수와 각종 메쏘드들.
}

어차피 singleton은 상속이 안 되니까, enum으로 해도 상관없고, 코드도 깔끔해졌습니다. 당근 serialize에 관련된 문제도 해결되었구요.

3. enum의 상속

enum은 기본적으로 상속이 안 됩니다. 상속이 되면 여러가지 문제가 발생할 수 있어서 상속을 없앴다고 합니다. 그러나 interface를 이용할 수는 있습니다.
ex>
public interface Direction{
    int getAngle();
}

public enum DefaultDirection implements Direction{
    동(90), 서(270), 남(180), 북(0);
    private final int angle;
    DefaultDirection (int angle){
        this.angle=angle;
    }
    public int getAngle(){
        return angle;
    }
}

public enum ComplexDirection implements Direction{
    동북(45), 서북(315) , 동남 (135) , 서남(225);
    private final int angle;
    ComplexDirection (int angle){
        this.angle=angle;
    }
    public int getAngle(){
        return angle;
    }
}


출처 - http://iilii.egloos.com/4835713






작년부터 안드로이드 공부를 하면서 조금씩 자바(java) 를 익혀가고 있다.

C++ 이랑 비슷하면서도 참 많이 다른 게 자바인데 그 중에 특히 enum 은 그동안 C++ 에서 불편해 하던 것이

다 구현도 있어서 참 편하다

 

예전에 C++ 관련 쓴 글은 아래 링크 참조

 

기본적인 enum 선언이나 사용법은 자바나 C++ 이나 비슷하다   

public enum Fruit {
    Banana, Apple, Lemon, Tomato, Melon;
}

간단한 과일을 enum 으로 선언했는데, 각 enum 에 어떻게 값이 들어 가는 지는 아래 테스트 코드로 확인 가능

// 간단한enum 확인용테스트코드
for (Fruit f : Fruit.values())
{
    Log.d("log","ordinal: " + f.ordinal());    
    Log.d("log","name: " + f.name());
}

  

 

C++ 처럼 자바도 enum 항목들이 0,1,2,3… 순서대로 저장되고 추가적으로 enum.name() 멤버 함수를 통해 enum 이름도 구할 수 있다.

사실 자바의 enum 은 class 이기 때문에 C++ 보다 훨씬 많은 기능이 가능하고, 예전에 C++ 에서 복잡하게 해 보려 했던 일들(위 링크 참조)이 기본적으로 구현되어 있다.

위 enum 선언을 조금 고쳐서 각 과일에 적당한 한글 이름과 색상 정보를 추가해 보자 .

public enum Fruit {

    Banana("바나나", "노랑"),
    Apple("사과", "빨강"),
    Lemon("레몬", "노랑"),
    Tomato("토마토", "빨강"),
    Melon("멜론", "초록");
   

    private String m_sName;
    private String m_sColor;    

    // 이름, 색상에맞는새로운생성자마련
    Fruit(String sName, String sColor)
    {
        m_sName = sName;
        m_sColor = sColor;
    }

    // 과일색상가져오기함수
    public String getColor()
    {
        return m_sColor;
    }

    // 과일이름가져오기함수
    public String getName()
    {
        return m_sName;
    }
}


코드는 정말 간단 ^^;

enum 옆에 ("바나나", "노랑") 같은 2가지 인자가 추가되었는데,

이처럼 자바는 enum 의 각 항목에 추가적인 정보를 개수 상관없이 마음대로 추가할 수 있다.

물론, 2가지 정보를 추가했기 때문에 enum 생성자를 변경해야 한다

Fruit(String sName, String sColor)

 

이제 각 enum 별로 위 생성자대로 초기화가 진행 되어 각 항목별로 멤버 변수에 값이 할당 된다.

추가된 정보가 잘 들어 갔는지 확인하는 테스트 코드.

// 테스트코드
for (Fruit f : Fruit.values())
{ 
    Log.d(
"log","ordinal: " + f.ordinal());
    Log.d("log","name: " + f.name());            
    Log.d("log","한글이름: " + f.getName());
    Log.d("log","색상: " + f.getColor());
}

위 코드처럼 실행하면 아래 그림처럼, enum 의 각 항목 별로 순서, 원래 이름, 한글 이름, 색상까지 잘 나온다.


자바 enum 의 이러한 확장 기능을 잘 이용하면

데이터를 구분 짓는 ID 와 그 ID 와 연관된 추가적인 정보를 잘 관리 할 수 있어 정보를 체계적으로 다루는 데 아주 용이하다

(물론, 구조체나 클래스로 얼마든지 만들 수 있지만, 기본적으로 언어에서 제공한다는 것은 그만큼 사용하기 편하다는 뜻임)


출처 - http://eslife.tistory.com/537






간단한 선언
예)

  1. public enum Types {  
  2.  TYPE1, TYPE2, TYPE3;  
  3. }  

String 값을 대입
선언 예)
  1. public enum Types {  
  2.  TYPE1("Type 1"),  
  3.  TYPE2("Type 2"),  
  4.  TYPE3("Type 3");  
  5.   
  6.  private String name;  
  7.  Types(String name) {  
  8.   this.name = name;  
  9.  }  
  10.   
  11.  @Override  
  12.  public String toString() {  
  13.   return name;  
  14.  }  
  15. }  

사용 예)
  1. package com.enumtest;  
  2.   
  3. public class EnumTest {  
  4.  public static void main(String[] args) throws Exception {  
  5.   Types type = Types.TYPE1;  
  6.   System.out.println(type);  
  7.  }  
  8. }  

결과: 
Type 1


출처 - http://tjjava.blogspot.kr/2012/06/enum.html







열거형 상수 (enum 타입) 정의 예제


파일명: Foo.java
public class Foo {
  enum Week { 월, 화, 수, 목, 금, 토, 일 }    // 끝에 세미콜론(;)을 붙이지 않음
  enum RGB { red, green, blue }

  public static void main(String args []) {

    // Week 이라는 새로운 자료형으로 Day 라는 변수를 만들어, "금"을 대입.
    Week Day = Week.금;
    System.out.println(Day + "요일");  // 출력 결과: 금요일
    System.out.println(RGB.blue);      // 출력 결과: blue

    System.out.println(Week.토);       // 출력 결과: 토

    Day = Week.일;
    System.out.println(Day);           // 출력 결과: 일

  }
}



열거형 상수 즉 Enumeration 이란, 미리 정해진 일정한 값을 가진 새로운 자료형을 사용자가 직접 만드는 것입니다.

문자열로 정의되어 있지만 내부적으로는 정수로 취급되기에, 일반 배열로 처리할 때보다 속도가 빠릅니다.

가령 일주일은 7개의 요일만 있고, 빛의 삼원색 (RGB) 은 3가지의 색으로만 이루어져 있기에, 이런 데이터를 다룰 때에는 열거형 상수로 정의하여 사용하면 이상적입니다.


상수이기에
Week.토 = Week.일;
이런 대입은 안됩니다. 그러면 Foo.java:12: cannot assign a value to final variable 토 이런 에러가 납니다.


enum 은 반드시 메소드 외부에서 정의해야 합니다. 그렇지 않으면 Foo.java:5: enum types must not be local 이런 에러가 납니다.


자바 버전 5.0 (=1.5) 이상에서만 Enumeration 이 지원됩니다.



출처 - http://mwultong.blogspot.com/2006/10/java-enum-enumeration.html








[번역]자바 Enum의 10가지 예제

원본글 : http://javarevisited.blogspot.sg/2011/08/enum-in-java-example-tutorial.html

자바의 Enumeration(Enum)은 JDK 1.5에 소개되었고, J2SE5에서 내가 가장 좋아하는

특징 중 하나이다.

타입처럼 Java Enum은 NEW,PARTIAL,FILL,FILL or CLOSED와 같은 주문의

대표적인 상태의 예와같이 확실한 상황하에서 더욱 적합하다.

Enumeration(Enum)은 원래 자바에서 이용하지 않았고,  C나 C++같은 다른 언어에서

사용했다.

하지만 결국 자바는 깨닫게 되었고 enum keyword에 의해 JDK 5안에 Enum이 소개되었다.

이 Java enum 튜토리얼안에서 우리는 자바안의 다른 enum 예를 볼 수 있을 것이고

자바안의 enum 사용에 대해 배울 수 있다.

자바안에 Enum에 의해 공급된 다른 특징들과 그것들을 어떻게 사용해야 되는지가

이 Java enum 튜토리얼의 초점이 될 것이다.

만약 당신이 자바 enum을 불편하게 느끼지 않는 것보다 전의 C 혹은 C++에서

Enumeration을 사용하고 있다해도,자바안의 Enum에 대한 나의 의견은

어느 다른 언어보다도 더 다채롭고 다용도로 쓰일 것이다.

  • Java enum 없이 어떻게 enumberable을 표현하는가

자바 enum이 자바 1.5로부터 사용된 이래로, 그것의 가치는 JDK1.5이전의 자바 안

enumerable value를 어떻게 보여주어서 사용할지 혹은 그것이 없이 사용할지에 대한

부분에 대해서 논의했다.

나는 behavior같은 enum을 모방해서 public static final 상수를 사용했다.

개념을 더욱 명확히 이해하기 위해 자바안의 enum 예제를 살펴보자

이 예제에서 우리는 PENNY (1) NICKLE (5), DIME (10), and QUARTER (25) 같이

값을 가지는 열거형처럼 US 통화코인을 사용할 것이다.

1
2
3
4
5
6
7
8
9
10
11
12
class CurrencyDenom {
            public static final int PENNY = 1;
            public static final int NICKLE = 5;
            public static final int DIME = 10;
            public static final int QUARTER = 25;
 
      }
 
class Currency {
   int currency; //CurrencyDenom.PENNY,CurrencyDenom.NICKLE,
                 // CurrencyDenom.DIME,CurrencyDenom.QUARTER
}

이것이 우리의 목적을 어느정도 충족해주긴 하지만 몇가지 심각한 한계를 가지고 있다.

(1)No Type-Safety

모든것중에 첫번째는 타입에 대해 안전하지 않다는 것이다. 당신이 99 통화에 대해

어느 유효한 int value값을 할당하려 해도 저 값을 대표하는 coin이 없다.

(2) No Meaningful Printing 

이 상수에 대한 어느것의 값을 출력하는 것은  당신이 “NICKLE “대신에 “5”를 출력할 때

코인의 의미있는 이름 대신에 그것의 numeric 값을 출력하게 될 것이다

(3) No namespace

currencyDenom 상수에 접근하기 위해 우리는 단지 PENNY를 사용하는 대신에

CurrencyDenom.PENNY 클래스이름을 고쳐서 사용할 필요가 있다.

이것은 또한 JDK 1.5안에서 static import를 사용함으로 이루어지게 되었다.

자바 enum은 이 모든 한계에 대한 대답이다. 자바의 enum은 타입에 대해 안전하고,

의미있는 String 이름을 부여하며 자신의 namaspace를 가지고 있다.

지금 위의 예제를 자바 enum을 사용해서 다시 보자.

1
public enum Currency {PENNY, NICKLE, DIME, QUARTER};

여기 Currency는 우리의 enum이고 PENNY, NICKLE, DIME, QUARTER는 enum의 상수다.

enum상수 주변에 중괄호를 주목하라. 왜냐하면 enums는 자바의 클래스나 인터페이스

같은 타입이기 때문이다.

또한 우리는 클래스나 인터페이스처럼 enum을 위한 유사한 naming convention을 따를 것이고,

enum 상수들은 static final을 내재한 이후로 우리는 자바안의 상수처럼 그들을 표시하기 위해

모두 대문자로 사용한다.

  • 자바안의 Enum은 무엇인가?

지금 “자바안의 enum은 무엇인가“에 대한 기본적인 질문으로 돌아가는 것이

자바의 키워드이며, 자바 enum에 대한 더욱 자세한 조항은 클래스나 인터페이스와 같은 타입이고

enum 상수로 정의해 사용할 수 있다.

enum 상수에 static과 final이 내재되어 있고, 당신은 한번 만들어지면 값을 바꿀 수 없다.

자바안의 Enum은 타입에 대해 안전하고 int 변수처럼 switch statement안에서 사용된다.

enum은 너가 변수 이름처럼 사용할 수 없는 키워드이며, JDK1.5에 소개된 이후로 너의 모든 이전 코드는

변수 이름과 같은 enum은 돌아가지 않을 것이고 리팩토링할 필요가 있을 것이다.

  • 자바의 Enum에 대한 이익

1) Enum은 타입에 대해 안전하다. 당신은 미리 정의된 enum 변수안의 상수외 다른 것을 할당할 수 없다.

2) Enum은 그 자신의 name-space를 가진다.

3) Enum의 가장 큰 특징은 int나 char같이 원시타입처럼 switch statememt 안에서 Enum을 사용할 수 있다.

4) 자바의 Enum은 새로운 상수를 추가하기가 쉽고, 기존에 존재하는 코드를 고치지 않고 새로운 상수를 추가할

수 있다.

  • 자바의 Enum에 대한 중요한 점

1) 자바안의 Enums는 타입에 대해 안전하고 자신의 name-space를 가진다. 그것은 enum이 type값을 가진다는 것이고

아래 “Currency” 예제에서 Enum 상수안에 명기된 것 외 어떤 다른 값도 할당할 수 없다

1
2
3
public enum Currency {PENNY, NICKLE, DIME, QUARTER};
Currency coin = Currency.PENNY;
coin = 1; //compilation error

2) 지바안의 Enums는 클래스 혹은 인터페이스처럼 타입을 참조한다. 생성자를 정의할 수 있고, 자바 enum안의 메서드나 변수는

자바의 enum type의 다음 예제에서 보여준 것처럼 C나 C++안의 Enum보다 더욱 파워풀하게 만든다

3) 아래 예제에서 보는 것처럼 만들때 enum 상수에 값을 명기할 수 있다.

1
public enum Currency {PENNY(1), NICKLE(5), DIME(10), QUARTER(25)};

그러나 멤버변수나 생성자를 이용할 필요가 있을 때 이것을 해야한다. 왜냐하면 PENNY(1)은 정말로 아래 예제에서 보는 것처럼

int value를 가지는 생성자를 호출하기 때문이다.

1
2
3
4
5
6
7
8
public enum Currency {
        PENNY(1), NICKLE(5), DIME(10), QUARTER(25);
        private int value;
 
        private Currency(int value) {
                this.value = value;
        }
};

자바 enum의 생성자는 private이고, 다른 접근제어자는 에러가 나올 것이다. 지금 각 코인에 연결된 값을 가져오기 위해 어느 평범한

자바 클래스처럼 자바 enum안에 public getValue()메서드를 정의할 있다. 또한 첫번째 라인의 세미콜론은 선택이다.

4) Enum 상수들은 static과 final을 내재하고 한번 만들어지면 바꿀 수 없다. 아래 코드는 에러를 뱉어낼 것이다

1
2
Currency.PENNY = Currency.DIME;
The final field EnumExamples.Currency.PENNY cannot be re assigned.

5) 자바의 Enum은 int, char처럼 switch statement의 인자로 사용할 수 있다. 이런 특징은 switch문에서

매우 유용하다. switch statement에서 java enum을 어떻게 사용하는지 아래 예를 보자

1
2
3
4
5
6
7
8
9
10
11
12
13
14
Currency usCoin = Currency.DIME;
    switch (usCoin) {
            case PENNY:
                    System.out.println("Penny coin");
                    break;
            case NICKLE:
                    System.out.println("Nickle coin");
                    break;
            case DIME:
                    System.out.println("Dime coin");
                    break;
            case QUARTER:
                    System.out.println("Quarter coin");
    }

6) enum안에 정의된 상수들은 final이고, 비교할때는 “==”를 사용한다.

1
2
3
4
5
Currency usCoin = Currency.DIME;
    if(usCoin == Currency.DIME){
       System.out.println("enum in java can be"+
               "compared using ==");
    }

7) 자바 컴파일러는 자동으로 모든 enum을 위한 static values() 메서드를 제공한다.

Values() 메서드는 enum 상수의 배열을 리턴한다. values()를 사용해서 enums의 값들을

배열을 돌면서 사용할 수 있다.

1
2
3
4
5
6
7
8
for(Currency coin: Currency.values()){
        System.out.println("coin: " + coin);
    }
And it will print:
coin: PENNY
coin: NICKLE
coin: DIME
coin: QUARTER

enums안에 정의된 순서와 동일하다는 것에 주목하라

8) Enum은 메서드를 오버라이드 할 수 있다. 아래예제처럼 enum안에 toString()메서드를

오버라이드 해서 enums 상수들을 위한 의미있는 설명을 제공하고 있다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
@Override
  public String toString() {
       switch (this) {
         case PENNY:
              System.out.println("Penny: " + value);
              break;
         case NICKLE:
              System.out.println("Nickle: " + value);
              break;
         case DIME:
              System.out.println("Dime: " + value);
              break;
         case QUARTER:
              System.out.println("Quarter: " + value);
        }
  return super.toString();
 }
};

그리고 여기 그것이 어떻게 보여지는지 나와있다.

1
2
3
4
5
Currency usCoin = Currency.DIME;
System.out.println(usCoin);
 
output:
Dime: 10

9) 두개의 새로운 컬렉션 클래스 EnumMap과 EnumSet은 추가되었고, 자바 enum을 지원하기 위해 컬렉션

패키지에 추가되었다. 이러한 클래스들은 자바의 Map과 Set 인터페이스에서 높은 성능을 보이며 우리는

어떤 기회에서든지 이것을 사용할 수 있다

10) 자바의 new 연산자를 사용해서 객체를 생성할 수 없다. 왜냐하면 Enum의 생성자가 private이고

Enums 상수는 오직 Enums 그 자신 안에서는 만들어질 수 있다.

11) 자바 enums의 객체는 어떤 enums 상수가 코드안에서 처음 호출되거나 참조될 때 만들어진다.

12) 자바의 Enum은 인터페이스를 구현하고 평범한 클래스처럼 어느 메서드라도 오버라이드 할 수 있다.

그것은 또한 Serializable과 Comparable 인터페이스 둘다 구현을 내재하고 있다.

java enum을 사용하여 인터페이스를 어떻게 구현하는지 아래 예를 보자

1
2
3
4
5
6
7
8
9
10
11
public enum Currency implements Runnable{
  PENNY(1), NICKLE(5), DIME(10), QUARTER(25);
  private int value;
  ............
 
  @Override
  public void run() {
  System.out.println("Enum in Java implement interfaces");
 
   }
}

13) 자바의 enum안에 추상메서드도 정의할 수 있다. 또한 enum의 다른 객체를 위해 다른

구현을 제공할 수도 있다. 아래 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
27
28
29
30
31
public enum Currency implements Runnable{
          PENNY(1) {
                  @Override
                  public String color() {
                          return "copper";
                  }
          }, NICKLE(5) {
                  @Override
                  public String color() {
                          return "bronze";
                  }
          }, DIME(10) {
                  @Override
                  public String color() {
                          return "silver";
                  }
          }, QUARTER(25) {
                  @Override
                  public String color() {
                          return "silver";
                  }
          };
          private int value;
 
          public abstract String color();
 
          private Currency(int value) {
                  this.value = value;
          }
          ..............
  }

이번 예에서 모든 코인은 color() 추상메서드를 만들어 다른 컬러를 가지게 될 것이고, 자신의 컬러가

정의된 enum 객체를 가지게 될 것이다.

color()메서드를 호출해서 어느 코인의 컬러를 아래예처럼 가져올 수 있다.

1
System.out.println("Color: " + Currency.DIME.color());
  • Enum valueof의 예

나의 구독자 중에 한명이 enum에서 String을 바꾸는valueOf메서드에 대해 언급되지 않았다는 걸 알려주었다.

여기 그가 제안한게 있다.

“enum의 valueOf()메서드를 포함할 수 있다. valueOf()는 static 메서드이고 String 인자값을 가지고

enum안에 String을 바꿔 사용할 수 있다.

한가지 생각해야 할건 enum의 valueOf(String)메서드는

“Exception in thread “main” java.lang.IllegalArgumentException: No enum const class

예외를 던질수 있다는 것이다.

ordenal()과 name() 유틸리티 메서드에 제안한 또 다른 독자는 Ordinal은 enum 상수의 포지션(순서)

를 리턴해주고, 특별한 enum 상수를 만들때 정확한 스트링을 리턴하도록 name()이 선언되어 있다라고 한다

*자바 enum의 대해선 아래 블로그에 정리가 잘 되어 있으니 참고하세요




출처 - http://bluepoet.me/2012/07/18/%EB%B2%88%EC%97%AD%EC%9E%90%EB%B0%94-enum%EC%9D%98-10%EA%B0%80%EC%A7%80-%EC%98%88%EC%A0%9C/




'Development > Java' 카테고리의 다른 글

java - jar  (0) 2012.11.09
java 로드맵  (0) 2012.11.07
java - @Override  (0) 2012.11.03
java - 문자열, 숫자, 영문 배열 및 list 정렬(sort)  (0) 2012.11.02
java - 클래스 구조 및 헬퍼 클래스(helper class)  (0) 2012.10.30
Posted by linuxism
,