[Java] Enum에 대하여.
0. 들어가며🏃
지난 글에서 상수를 관리하는 방법으로 유틸리티 클래스를 사용하는 방식을 살펴보았습니다.
상수를 선언하기 위한 유틸리티 클래스는 직관적이고 그럴듯해 보이지만 몇몇 상황에서 불편한 점이 있습니다. 예시 코드를 통해서 한번 살펴보도록 하죠.
class Fruit { // 정수 열거 패턴
static final int APPLE = 1;
static final int GRAPE = 2;
static final int STRAWBERRY = 3;
}
class Company { // 정수 열거 패턴
static final int APPLE = 1;
static final int SAMSUNG = 2;
static final int GOOGLE = 3;
}
public class ConstantTest {
public static void main(String[] args) {
if (Fruit.APPLE == Company.APPLE) // 으음..?
System.out.println("둘 다 사과긴한데..");
}
}
위 코드는 Fruit 클래스와 Compay 클래스를 통해 상수들을 정의해주고 Fruit 클래스의 Apple과 Company 클래스의 Apple이 같은지 비교해보는 코드입니다. 두 값 모두 실제로는 정수 1을 값으로 가지고 있으니 if문 안에 조건은 참이 되어버리죠.
이 상황이 상당히 거슬립니다. 애초에 과일인 사과와 회사인 Apple은 다른 것인데 코드 상으로는 같은 값을 가지고 있으니 두 상수가 같다고 나와버리기 때문이죠. 당장 문제를 해결하기 위해 Company 클래스의 각 상수값을 4, 5, 6로 바꾸는 방법도 있겠지만 상당히 찝찝한 해결책입니다..
Fruit 클래스와 Company 클래스의 각 상수들은 각자 과일과 회사라는 Context 하에 정의된 것들인데 위와 같은 방식으로는 해당 Context를 담아낼 방법이 없습니다. 위와 같은 방식은 type safety가 보장이 되지 않는 상수 선언 방식이다 라고도 말할 수 있을 것 같습니다.
이러한 선언 방식을 개선하기 위해 아래와 같이 객체를 사용해볼 수도 있을 것 같습니다.
class Fruit {
static final Fruit APPLE = new Fruit();
static final Fruit GRAPE = new Fruit();
static final Fruit STRAWBERRY = new Fruit();
}
class Company {
static final Company APPLE = new Company();
static final Company SAMSUNG = new Company();
static final Company GOOGLE = new Company();
}
public class ConstantTest {
public static void main(String[] args) {
if (Fruit.APPLE == Company.APPLE) // 컴파일 에러!
System.out.println("둘 다 사과다!");
}
}
처음 봤던 방식보다는 좀 더 상수에 Context를 담아낼 수 있는 방식이지만 여전히 기능적으로 아쉬운 부분이 있습니다. 이를 좀 더 보완하면 좋은 방식이 될 것만 같은 냄새가 납니다!
그러면 이제부터 Enum에 대해 알아보도록 하겠습니다.
1. Enum에 대하여📚
Java의 Enum은 서로 관련된 상수를 편리하게 선언하기 위해 JDK1.5부터 추가된 기능입니다. 열거형이라고도 불리는 Enum은 C/C++에도 존재하지만, Java에서의 Enum은 C/C++ 보다 많은 기능을 제공해주고 있습니다. 먼저 Enum의 제일 간단한 예시부터 살펴보도록 하겠습니다.
enum Company {
APPLE, SAMSUNG, GOOGLE;
}
public class EnumTest {
public static void main(String[] args) {
System.out.println(Company.APPLE); // APPLE
}
}
엄청 간단하죠?? 선언과 참조 모두 매우 간단합니다. 이제 enum을 좀 더 활용해보도록 하겠습니다. 활용에 앞서 Enum이 실제로 어떤 녀석인지 살펴보면 활용을 이해하는데 도움이 되어, enum이 내부적으로 어떻게 구현되어 있는지에 대해 먼저 알아보겠습니다.
2. Enum의 구현 방식👻
enum Company { APPLE, SAMSUNG, GOOGLE; }
// eunm을 클래스로 정의한다면 아래와 같은 모양
class Company {
static final Company APPLE = new Company("APPLE");
static final Company SAMSUNG = new Company("SAMSUNG");
static final Company GOOGLE = new Company("GOOGLE");
private String name;
private Company(String name) {
this.name = name;
};
}
위 코드는 enum이 클래스로 정의되어 있다면 저런 형식일 것임을 보여주고 있습니다. 객체를 통해 상수를 선언하고 private 생성자를 통해 추가적인 인스턴스 생성을 방지하고 있습니다. 또한 위와 같은 형태를 사용함으로써 type safety 효과를 얻고 있습니다.
그럼 이제 enum의 내부 형태가 위와 같은 형식을 따를 것이라고 머리에 기억해두고 enum의 활용에 대해 살펴보도록 하겠습니다.
3. Enum의 활용😀
enum의 내부 구현이 위와 같다면 필드와 메서드를 추가해볼 수도 있겠는데요. enum에 필드와 메서드를 추가함으로써 선언한 상수에 추가적인 데이터를 내제시키고, 원하는 행위를 할 수 있도록 정의할 수 있습니다. 어려우니 예시로 살펴보도록 하겠습니다.
import static Fruit.*;
enum Fruit {
APPLE("RED", 1), GRAPE("PURPLE", 2), WATERMELON("GREEN", 1.5);
final private String color;
final private double costPerKilogram; // 과일의 1kg 당 가격 정보
Fruit(String color, double costPerKilogram) { // 생성자
this.color = color;
this.costPerKilogram = costPerKilogram;
}
public String getColor() { return color; }
public double getCostPerKilogram() { return costPerKilogram; }
public double calcCost(int kilogram) { // 과일의 비용을 계산하는 메서드
return kilogram * costPerKilogram;
}
}
public class EnumTest {
public static void main(String[] args) {
int kilogramToBuy = 10;
System.out.println(WATERMELON.calcCost(kilogramToBuy)); // 15
}
}
위 코드는 Fruit enum을 통해 과일과 관련된 상수를 정의하고, 과일의 색, 1kg 당 가격 정보를 필드에 선언함으로써 각 과일 상수에 추가적인 정보를 내제시킨 예시입니다. 또한 calcCost라는 메서드를 추가해 클라이언트가 원하는 kg을 넣어주면 과일의 총 가격도 나올 수 있도록 해주었습니다.
이처럼 enum을 조금만 더 활용하면 단순 상수 기능 이외에도 다양한 기능을 추가해서 사용할 수 있게 됩니다.
🚩추가로..
Java Enum에 대해 알아보다 활용에 대한 좋은 글이 있어 관심이 가신다면 아래 글을 읽어보시면 좋을 것 같습니다!
4. 나가며💨
오늘은 Java의 Enum에 대해 글을 써보았습니다.
enum을 사용하면 type safety한 상수를 선언할 수 있고, 상수 스스로가 클라이언트에게 다양한 기능을 제공하게끔 만들 수 있습니다. 또한 IDE의 도움을 받아 편하게 사용도 가능하죠. 이외에도 여러 장점을 가진 enum에 대해 공부해보니 다양한 활용 사례도 많이 찾을 수 있었고, 적용했을 때 얻는 이득이 많다고 느껴집니다. 잘 기억해두고 활용해보면 좋을 것 같네요.