(Valid Java) Point 34. int 상수 대신 열거형을 사용하라.

Point 34. int 상수 대신 열거형을 사용하세요.

  • 가장 단순한 열거형
    public enum Apple { FUJI, PIPPIN, GRANNY_SMITH }
    public enum Orange { NAVEL, TEMPLE, BLOOD }

    Java의 열거형은 완전한 형식의 클래스이므로 다른 언어의 열거형보다 훨씬 강력합니다.

    실제로 열거형은 외부에서 액세스할 수 있는 생성자를 제공하지 않습니다.

    final오전.

    따라서 클라이언트가 인스턴스를 직접 생성하거나 확장할 수 없기 때문에 열거형 선언으로 생성된 인스턴스는 하나만 존재함을 보장합니다.

    만약에. Apple 열거 유형을 매개변수로 사용하는 메소드를 선언할 때 전달되는 참조는 다음과 같습니다.

    Apple확실한 것은 이것이 세 가지 가치 중 하나라는 것입니다.

    다른 유형의 값을 전달하려고 하면 컴파일 타임 오류가 발생합니다.

  • 데이터 및 메서드가 포함된 열거형

    public enum Planet {
      MERCURY(3.302e+23, 2.439e6),
      VENUS  (4.869e+24, 6.052e6),
      EARTH  (5.975e+24, 6.378e6),
      MARS   (6.419e+23, 3.393e6),
      JUPITER(1.899e+27, 7.149e7),
      SATURN (5.685e+26, 6.027e7),
      URANUS (8.683e+25, 2.556e7),
      NEPTUNE(1.024e+26, 2.477e7);
    
      private final double mass;           // 질량(단위: 킬로그램)
      private final double radius;         // 반지름(단위: 미터)
      private final double surfaceGravity; // 표면중력(단위: m / s^2)
    
      // 중력상수(단위: m^3 / kg s^2)
      private static final double G = 6.67300E-11;
    
      // 생성자
      Planet(double mass, double radius) {
          this.mass = mass;
          this.radius = radius;
          surfaceGravity = G * mass / (radius * radius);
      }
    
      public double mass()           { return mass; }
      public double radius()         { return radius; }
      public double surfaceGravity() { return surfaceGravity; }
    
      public double surfaceWeight(double mass) {
          return mass * surfaceGravity;  // F = ma
      }
    }

    열거된 각 유형 상수를 특정 데이터와 연결하려면 생성자로부터 데이터를 수신하고 인스턴스 필드에 저장하기만 하면 됩니다.

위의 행성 예제에 표시된 속성은 연관 유형이 사용되는 대부분의 상황을 잘 설명합니다.

그러나 더 많은 기능을 제공하기 위해 상수를 원할 때가 있습니다.

  • 값으로 분기하는 enum 유형 – 만족하십니까?

    public enum Operation {
      PLUS, MINUS, TIMES, DIVIDE;
    
      public double apply(double x, double y){
          switch (this){
              case PLUS: return x+y;
              case MINUS: return x-y;
              case TIMES: return x*y;
              case DIVIDE: return x/y;
          }
          throw new AssertionError("알 수 없는 연산: " + this);
      }
    }

    위의 소스는 작동하지만 다른 작업을 추가하려면 case 문을 추가해야 합니다.

    case 문을 잊어버리고 추가하지 않으면 컴파일 타임 오류가 발생하지 않으며 실행 유형 중에 “알 수 없는 작업” 오류가 발생합니다.

    따라서 각 상수에 대한 클래스 본문, 즉 각 상수에서 다시 정의하는 방법이 있습니다.

  • 상수로 메서드를 구현한 열거형

    public enum Operation2 {
      PLUS { public double apply(double x, double y){ return x+y; } },
      MINUS { public double apply(double x, double y){ return x-y; } },
      TIMES { public double apply(double x, double y){ return x*y; } },
      DIVIDE { public double apply(double x, double y){ return x/y; } };
    
      public abstract double apply(double x, double y); // 추상 메서드를 선언
    }

    위와 같은 추상 메소드 apply다른 작업을 추가할 때 메소드 구현을 추가하지 않는 경우.

    컴파일 오류가 없기 때문에 안전합니다.

참고 자료

Joshua Bloch, 『Effective Java 3/E』, 잘 번역됨, Programming Insight (2018)
http://www.kyobobook.co.kr/product/detailViewKor.laf?ejkGb=KOR&mallGb=KOR&barcode=9788966262281&orderClick=LEa&Kc=