느린 것을 걱정하지 말고, 멈춰서는 것을 걱정하라
article thumbnail

 

 최근 토비의 스프링을 공부하는데 enum을 사용하는 경우를 가끔씩 볼 수 있다. enum을 사용할 줄은 알지만 정확히 잘 사용하지는 못하는지라 이참에 enum에 대해서 제대로 숙지하기 위해 블로그 포스팅을 하면서 고찰을 해보고자 한다.

 

 이러한 고찰을 하는 이유는 드라마 브레인에서 이강훈의 대사처럼 할 수 있는것과 잘하는 것은 다르기 때문이다. 잘 숙지하고 의식적으로 필요할 경우 enum을 사용하여 할 수 있는경지가 아닌 잘하는 경지가 되도록 하겠다.

 

열거 자료형(enumerated type)은 고정 개수의 상수들로 값이 구성되는 자료형이다. 상수들의 모임이라면 내 개인적인 생각으로는 그냥 클래스에 아래와 같이 상수를 넣으면 되지 않을까 생각하였다.

 

ex)

 

 public static final int USER_ADMIN=1;

 public static final int USER_DEFAULT=2;

 public static final int USER_CLIENT =3;



 public static final int ROLE_ADMIN=1;

 public static final int ROLE_DEFAULT=2;

 public static final int ROLE_CLIENT =3;

 

그러나 Effective JAVA에서는 이 기법을 int enum 패턴이라고 부르는데  안전성 관점과 편의성 관점에서 단점이 많다고 한다.

 

단점

  1. 별도의 이름공간을 제공하지 않기 때문에 접두어를 붙이게 된다.

  2. 컴파일 시점 상수이기 때문에 상수를 사용하는 클라이언트 코드와 함꼐 컴파일 되어서 깨지기 쉽다.

  3. 인쇄 가능한 문자열로 변환하기 쉽지 않다.

 

이러한 문제점을 해결한 것이 자바 1.5에 나온 enum 자료형이다.

 

ex)

 

public enum User {ADMIN, DEFAULT, CLIENT}

public enum Role {ADMIN,DEFAULT,CLIENT}

 

 자바의 enum 자료형은 완전한 기능을 갖춘 클래스로 열거 상수별로 하나의 객체를 public static final 필드 형태로 제공하는 것이다. enum 자료형은 실질적으로는 final로 선언된 것이나 마찬가지인데, 클라이언트가 접근할 수 있는 생성자가 없기 때문이다. 참고로 안에 있는 자료형들은 String이나 int등의 자료형이 아닌 enum 자료형 그 자체이다. 

 

ex)

enum 자료형의 자료형 확인해 보기예제이다.

public class MyTest {
	 enum User {ADMIN, DEFAULT, CLIENT}

	public static void main(String[] args) {
		for(User user : User.values()) {
			System.out.println(user.name()+" "+user.getClass().getTypeName());
		}
		System.out.println("문자열"+" "+"문자열".getClass().getTypeName());
	}
}

 

결과)

 

enum 자료형의 특징

  1. enum자료형으로는 새로운 객체를 생성하거나 계승을 통한 확장을 할 수 없기때문에 이미 선언된 enum상수 이외의 객체는 사용할 수 없다.

  2. enum 자료형은 컴파일 시점 형 안전성을 제공한다. 만약 USER형 인자를 받는다면 3개의 인자중 하나만 받는다.

  3. 싱글턴 패턴을 일반화 한 것으로 열거 상수가 하나뿐이다.

  4. enum 자료형은 같은 이름의 상수가 공존할 수 있도록 한다. 네임스페이스가 이들을 분리시켜 주기 때문이다.

  5. int enum패턴과 달리 상수의 값이 클라이언트 코드와 함께 컴파일되는 일이 생기지 않는다.

  6. enum 자료형은 toString 메서드를 호출하면 인쇄 가능 문자열로 쉽게 변환할 수 있다.

  7. enum자료형은 상수묶음에서 시작해서 점차로 완전한 기능을 갖춘 추상화 단위로 진화할 수 있다.

 

enum 사용하기

enum 상수에 데이터를 넣으려면 객체 필드를 선언하고 생성자를 통해 받은 데이터를 그 필드에 저장하면 된다.

 

 

ex)

각 enum 상수의 객체필드를 선언 후, 생성자를 통해 데이터를 저장 후 사용하는 예제이다. 각 필드는 private로 두고 public 접근자 메서드를 이용해서 접근하도록 하는 관례를 따라 소스코드를 작성하였다.

 

public class MyTest {
      	enum Planet{
              MERCURY(1,2), SUN(1,3), EARTH(2,2);
              
              private final double width;
              private final double height;
              private final double PI=3.14;
              
              private Planet(double w,double h) {
                     this.width=w;
                     this.height=h;
              }
              public double getWidth() {
                     return this.width;
              }
              public double getHeight() {
                     return this.height;
              }
              public double widheiPI() {
                     return width*height;
              }
       }
       public static void main(String[] args) {
              for(Planet p : Planet.values()) {
                     System.out.println(p);
              }
       }
}

 

 

 

enum 자료형은 메서드 안에서 실제 메서드를 재정의 하는 기능을 갖고있는데 이를 상수별 메소드 구현이라고 부른다.

 

ex)

상수별 메소드 구현을 이용하여 사칙연산을 구하는 열거형 만들기

public class OperationTest {
       enum Operation{
              PLUS("+"){
                     @Override
                     double apply(double x, double y) {
                           return x+y;
                     }
              },
              MINUS("-"){
                     @Override
                     double apply(double x,double y) {
                           return x-y;
                     }
              },
              TIMES("*"){
                     @Override
                     double apply(double x,double y) {
                           return x*y;
                     }
              },
              DIVIDE("/"){
                     @Override
                     double apply(double x,double y) {
                           return x/y;
                     }
              };            
              private final String symbol;            

              private Operation(String symbol) {
                     this.symbol=symbol;
              }           

              @Override
              public String toString() {
                    return symbol;
              }
              abstract double apply(double x,double y);
       }

       public static void main(String[] args) {
              double a=1;
              double b=2;
              
              for(Operation op:Operation.values()) {
                     System.out.printf("%f %s %f = %f %n",a,op,b,op.apply(a, b));
              }
       }
}

 

결과)

 

 

profile

느린 것을 걱정하지 말고, 멈춰서는 것을 걱정하라

@주현태

포스팅이 좋았다면 "좋아요❤️" 또는 "구독👍🏻" 해주세요!