개발자는 기록이 답이다
🐙 Java의 enum은 뭘까? 어떤 상황에서 enum을 사용하면 좋을까? 본문
Java의 Enum을 언제 사용하는게 좋을까?
- Java의 enum은 자바 5부터 도입되었으며 열거형(Enumeration)의 약자이다.
- 서로 연관된 상수들의 집합을 나타낸다.
- 정의한 상수 값 의외에는 허용하지 않는 타입이다(type-safe)
- 싱글톤 패턴을 구현할때 사용하기도 한다
도메인 설계 시 사용하는 인스턴스 수가 정해져 있고, 관련된 걸 처리할 수 있는 상수값이 여러개가 존재할때 사용한다.
1. 상수 집합의 표현
서로 관련된 상수를 묶어서 나타내므로 코드를 읽고 이해하기 쉽게 만든다.
public enum Days {
MONDAY, TUESDAY, WEDNESDAY, THURSDAY, FRIDAY, SATURDAY, SUNDAY
}
2. Type-safe한 열거형
컴파일 타임에 타입 안전성을 보장하므로, 잘못된 값이나 형변환 오류를 방지할 수 있다.
Days today = Days.MONDAY;
3. Swtich문에서 활용
switch 문에서 사용될 때 가독성을 높여주며, 모든 상수에 대한 처리를 보장한다.
switch (today) {
case MONDAY:
// 처리
break;
case TUESDAY:
// 처리
break;
// ...
}
4. 열거형 상수 간의 비교
상수 간에 == 연산자를 사용하여 간단하게 비교할 수 있다.
if (today == Days.MONDAY) {
// 처리
}
5. API 설계 시 사용
고정된 상수 집합을 갖고 있는 경우에 API를 설계할 때 유용하게 활용될 수 있다.
6. 싱글톤 패턴 구현
간단하게 싱글톤 패턴을 구현할 수 있다.
public enum Singleton {
INSTANCE;
// 싱글톤의 동작과 관련된 메서드 등 추가 가능
}
Enum은 자바에서 열거형을 나타내는 데 사용되는 특별한 데이터 형식입니다. 이는 서로 관련된 상수들을 묶어서 표현할 수 있는데, 이것이 가독성을 높이고 코드를 더 직관적으로 만들어줍니다. 예를 들어, 요일을 표현하는 Enum이 있다면, 'MONDAY', 'TUESDAY'와 같이 명시적으로 값이 나열되어 있어 어떤 상수가 있는지 쉽게 파악할 수 있습니다.
또한, Enum은 자바에서 타입 안전성을 보장하면서 상수의 집합을 정의하는 데 유용하게 사용됩니다. Switch 문에서의 활용이나 열거형 상수 간의 비교도 간단하게 처리할 수 있어 코드의 안정성을 높이는 데 기여합니다.
더불어, Enum은 API를 설계할 때나 특정한 값의 집합이 고정되어 있는 경우에도 유용하게 활용될 수 있습니다. 싱글톤 패턴을 적용할 때에도 Enum을 사용하면 간단하게 구현할 수 있어서 유용하게 활용됩니다.
Enum을 이용한 "싱글톤 패턴"구현 방법
Enum을 이용한 싱글톤 패턴은 "Effective Java"에서 제안된 방법 중 하나로, 간결하면서도 안전한 싱글톤을 구현하는 방법이다.
싱글톤이란 ? 인스턴스를 오직 하나만 생성할 수 있는 클래스를 말한다.
그런데 클래스를 싱글턴으로 만들면 이를 사용하는 클라이언트를 테스트하기가 어려워질 수 있다.
타입을 인터페이스로 정의한 다음 그 인터페이스를 구현해서 만든 싱글턴이 아니라면 싱글턴 인스턴스를 mock구현으로 대체할 수 없기 때문이다.
싱글톤 패턴은 Enum 자체를 싱글톤 인스턴스로 초기화되며, 스레드 안전성과 직렬화에 대한 문제를 자연스럽게 다룬다.
예를 들어, Singleton이라는 Enum을 선언하면, 해당 Enum은 프로그램 내에서 유일한 인스턴스를 나타내게 된다. 아래와 같이 간단하게 구현할 수 있다.
public enum Singleton {
INSTANCE; // 유일한 인스턴스를 정의
// 이 Enum에서 사용할 필요에 따라 다른 멤버들을 추가할 수 있습니다.
public void doSomething() {
System.out.println("Singleton is doing something.");
}
}
Enum을 이용한 싱글톤 패턴은 인스턴스 생성과 관련된 안정성과 효율성을 고려할 때 효과적이다.
또한 아래아 같은 이유로 멀티스레드 환경에서의 안전성과 직렬화 처리를 고민하지 않아도 되기 때문에 코드의 안정성을 보장한다.
1. 스레드 안전성
Enum은 자바에서 스레드 안전성을 보장하므로, 별도의 동기화에 대한 고민이 필요하지 않다.
Enum은 클래스로서 정의되어 있으며, 내부 각 상수들은 해당 Enum의 static final 필드로 생성된다.
thread-safe한 이유는 JVM에서 클래스 로딩 시점에 초기화되며, 각 상수는 변경 불가능하고, 미리 정의된 상태로 생성되기 때문에 스레드 간에 공유해서 사용해도 문제가 없기 때문이다.
2. 직렬화 처리
Enum은 implements Serializable을 추가하지 않아도 JVM이 자체 직렬화를 보장한다.
- Enum의 직렬화
- Enum상수는 JVM이 처음 로드될 때 이미 인스턴스화되어 있다.
- 직렬화 시에 Enum은 그 자체로 객체를 표현하므로 추가적인 정보나 데이터를 저장할 필요가 없다.
- Enum의 역직렬화
- 역직렬화 시에 Enum은 클래스 로딩과 인스턴스 생성 과정이 안전하게 이루진다.
- Enum의 역직렬화는 클래스 로딩 시에 존재하는 상수 중 하나로만 제한되므로, 불필요한 객체 생성을 방지한다.
import java.io.*;
enum Days {
MONDAY, TUESDAY, WEDNESDAY, THURSDAY, FRIDAY, SATURDAY, SUNDAY;
}
public class SerializationExample {
public static void main(String[] args) throws IOException, ClassNotFoundException {
// 직렬화
ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
ObjectOutputStream objectOutputStream = new ObjectOutputStream(byteArrayOutputStream);
objectOutputStream.writeObject(Days.MONDAY);
// 역직렬화
ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream(byteArrayOutputStream.toByteArray());
ObjectInputStream objectInputStream = new ObjectInputStream(byteArrayInputStream);
Days deserializedDay = (Days) objectInputStream.readObject();
// 비교
System.out.println(Days.MONDAY == deserializedDay); // true
}
}
Days.MONDAY Enum 상수를 직렬화하고 역직렬화한 결과는 동일한 Enum 상수이다.
Enum은 클래스 로딩 시점에 이미 정의된 상태를 유지하고 있기 때문에, 역직렬화 과정에서 안전하게 복원된다.
이처럼 Enum의 직렬화는 클래스 로딩과 인스턴스 생성에 대한 안전한 처리를 기본적으로 제공하며, 이로써 Enum 타입은 직렬화/역직렬화 과정에서 안정성을 보장한다.
🤔느낀점
일반 클래스에서도 static final을 사용할 경우 캡슐화를 위반한다고 알고 있는데, "Enum의 필드들도 static final로 초기화될 경우 캡슐화를 위반하는게 아닐까?" 라고 생각했지만, Enum클래스 내부에서만 접근할 수 있기 때문에 캡슐화를 유지할 수 있다고 한다.
Enum은 상수로 사용되는 경우, 상수 값의 변경이나 외부에서 임의의 수정을 방지하기 위해 불변하게 설계되었다.
상수들의 집합이므로, 응집도가 높다고 할 수 있어서 많이 사용하는 것 같다.
정리 1 ) 특정 enum 타입을 가질 수 있는 모든 값을 순회할때 .values()메서드를 사용한다
정리 2 ) enum은 자바의 클래스처럼 생성자, 메소드, 필드를 가질 수 있다.
정리 3) enum의 값은 ==연산자로 동일성을 비교할 수 있다. 굳이 nullPointException이 날 수 있는 equals()를 사용하지 말아라.
정리 4) enum을 key로 사용하는 Map이나 Set을 이용할땐, EnumMap과 EnumSet을 사용한다. 여기서 확인
'언어 > Java' 카테고리의 다른 글
🐙 Checked Exception과 Unchecked Exception의 차이 (0) | 2023.12.22 |
---|---|
🐙 Java에서 Exception과 Error의 차이점 (0) | 2023.12.22 |
🐙 static 키워드를 잘못 사용했을 때 발생할 수 있는 문제와 올바른 사용법 (1) | 2023.12.21 |
🐙 Primitive 타입과 Reference 타입 (0) | 2023.12.21 |
🐙 오버로딩과 오버라이딩의 차이점 (0) | 2023.12.21 |