정수 열거 패턴: 자바에서 열거 타입을 지원하기 이전에는 “정수 상수”를 선언하여 열거 타입을 표현했다.
public class Fruits {
public static final int APPLE_FUJI = 0;
public static final int APPLE_PIPPIN = 1;
public static final int APPLE_GRANNY_SMITH = 2;
public static final int ORANGE_NAVEL = 3;
public static final int ORANGE_TEMPLE = 4;
public static final int ORANGE_BLOOD = 5;
}
===
public class FruitStore {
// 타입 안정성을 보장할 수 없다.
public int getPrice**~~(int fruit)~~** {
return switch (fruit) {
case Fruits.APPLE_FUJI -> 100;
case Fruits.APPLE_PIPPIN -> 200;
case Fruits.APPLE_GRANNY_SMITH -> 300;
case Fruits.ORANGE_NAVEL -> 150;
case Fruits.ORANGE_TEMPLE -> 250;
case Fruits.ORANGE_BLOOD -> 350;
default -> throw new IllegalArgumentException("No such fruit");
};
}
public String getNameOfFruit(int fruit) {
return switch (fruit) {
case Fruits.APPLE_FUJI -> "Fuji Apple";
case Fruits.APPLE_PIPPIN -> "Pippin Apple";
case Fruits.APPLE_GRANNY_SMITH -> "Granny Smith Apple";
case Fruits.ORANGE_NAVEL -> "Navel Orange";
case Fruits.ORANGE_TEMPLE -> "Temple Orange";
case Fruits.ORANGE_BLOOD -> "Blood Orange";
default -> throw new IllegalArgumentException("No such fruit");
};
}
public static void main(String[] args) {
FruitStore fruitStore = new FruitStore();
**~~System.out.println(fruitStore.getPrice(Fruits.APPLE_FUJI));~~**
}
}
정수 열거 패턴의 단점
• 타입 안전을 보장할 수 없다.
• 표현력이 좋치 않다.
• 프로그램이 깨지기 쉽다.
• 문자열로 출력하기 까다롭다.
• 모든 상수를 순회하는 방법도 마땅치 않다
열거 타입 선언으로 만들어진 인스턴스는 싱글턴이다.
컴파일타임 타입 안전성을 제공한다.
public enum Apple {
FUJI, PIPPIN, GRANNY_SMITH;
}
---
public class AppleClient {
public static void main(String[] args) {
FruitStore fruitStore = new FruitStore();
System.out.println(fruitStore.getPrice(Apple.PIPPIN));
// 이름 자체만으로도 return 이 가능하다.
**System.out.println(Apple.PIPPIN);**
}
}
---
public class FruitStore {
// 타입 안전성을 나타내지만 해당 처럼 코드를 쓰면 안됨 (본문)
public int getPrice(**Apple apple**) {
return switch (apple) {
case FUJI -> 100;
case PIPPIN -> 200;
case GRANNY_SMITH -> 300;
};
}
public int getPrice(Orange orange) {
return switch (orange) {
case NAVEL -> 150;
case TEMPLE -> 250;
case BLOOD -> 350;
};
}
}
열거 타입에 이름 공간을 있으니 (공간이 다른) 이름이 같은 상수도 공존할 수 있 다.
새로운 상수를 추가하거나 순서를 바꿔도 다시 컴파일 하지 않아도 된다.
toString 메서드는 출력하기 적절한 문자열을 제공한다.
메서드나 필드를 추가하고 인터페이스를 구현할 수도 있다.
public interface Fruit {
int getPrice();
}
===
public enum Apple implements Fruit {
FUJI(100), PIPPIN(120), GRANNY_SMITH(140);
private int price;
**// enum 의 생성자는 반드시 private
Apple(int price) {
this.price = price;
}**
@Override
public int getPrice() {
return this.price;
}
}
===
public enum Orange implements Fruit {
NAVEL(40), TEMPLE(35), BLOOD(20);
private final int price;
Orange(int price) {
this.price = price;
}
@Override
public int getPrice() {
return this.price;
}
}
==
public class FruitStore {
**public int getPrice(Fruit fruit) {
return fruit.getPrice();
}**
}
values 메서드를 사용해 정의되어 있는 모든 상수 배열을 사용할 수 있다.
// 어떤 객체의 지구에서의 무게를 입력받아 여덟 행성에서의 무게를 출력한다. (212쪽)
public class WeightTable {
public static void main(String[] args) {
double earthWeight = 10;
double mass = earthWeight / Planet.EARTH.surfaceGravity();
Planet[] values = Planet.values();
for (Planet p : values)
System.out.printf("%s에서의 무게는 %f이다.%n", p, p.surfaceWeight(mass));
}
}
===
// 코드 34-3 데이터와 메서드를 갖는 열거 타입 (211쪽)
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
}
}
열거 타입에서 상수를 제거한다면?
상수마다 동적아 달라져야 한다면?