자바 Enum

Jeongmin Yeo (Ethan)·2021년 1월 28일
3

STUDY HALLE

목록 보기
11/13
post-thumbnail

자바의 열거형에 대해 정리합니다.

백기선님과 함께하는 자바 11주차 스터디 과정입니다.

학습할 내용은 다음과 같습니다.

  • enum 정의하는 방법
  • enum이 제공하는 메소드
  • java.lang.Enum
  • EnumSet

References


1. enum 정의하는 방법

Enum은 특수한 데이터 타입으로 사전에 정의한 상수 집합입니다. Enum으로 정의한 변수는 사전에 정의한 값들 중 하나와 반드시 같아야 합니다.

가장 흔한 예로 나침판 방향이 있습니다. (values of NORTH, SOUTH, EAST, and WEST) Enum 타입의 필드 값들은 항상 대문자로 표시해야 합니다.

자바 프로그래밍에서 Enum 타입은 enum keyword를 통해 정의할 수 있습니다.

public enum Day {
    SUNDAY, MONDAY, TUESDAY, WEDNESDAY,
    THURSDAY, FRIDAY, SATURDAY 
}

다음으로 enum type을 사용하는 예제를 살펴보겠습니다.

public class EnumTest {
    Day day;
    
    public EnumTest(Day day) {
        this.day = day;
    }
    
    public void tellItLikeItIs() {
        switch (day) {
            case MONDAY:
                System.out.println("Mondays are bad.");
                break;
                    
            case FRIDAY:
                System.out.println("Fridays are better.");
                break;
                         
            case SATURDAY: case SUNDAY:
                System.out.println("Weekends are best.");
                break;
                        
            default:
                System.out.println("Midweek days are so-so.");
                break;
        }
    }
    
    public static void main(String[] args) {
        EnumTest firstDay = new EnumTest(Day.MONDAY);
        firstDay.tellItLikeItIs();
        EnumTest thirdDay = new EnumTest(Day.WEDNESDAY);
        thirdDay.tellItLikeItIs();
        EnumTest fifthDay = new EnumTest(Day.FRIDAY);
        fifthDay.tellItLikeItIs();
        EnumTest sixthDay = new EnumTest(Day.SATURDAY);
        sixthDay.tellItLikeItIs();
        EnumTest seventhDay = new EnumTest(Day.SUNDAY);
        seventhDay.tellItLikeItIs();
    }
}

// expected output
Mondays are bad.
Midweek days are so-so.
Fridays are better.
Weekends are best.
Weekends are best.

enum class body에는 methods와 fields가 포함될 수 있습니다. 그리고 컴파일러는 자동으로 enum class를 만들 때 모든 enum 값이 선언된 순서대로 포함된 배열을 반환하는 static values method를 추가해줍니다.

예는 다음과 같습니다.

for (Planet p : Planet.values()) {
    System.out.printf("Your weight on %s is %f%n",
                      p, p.surfaceWeight(mass));
}

enum은 그리고 내재적으로 java.lang.Enum 클래스를 상속하고 있습니다. 자바에서는 오로지 한 클래스만 상속할 수 있기 때문에 enum은 다른 클래스를 상속할 수 없습니다.

그리고 enum 클래스의 생성자의 접근 제어자는 package-private or private access 입니다. 그러므로 enum 인스턴스를 만들 때 자동적으로 상수를 만들어주기 때문에 생성자를 호출할 필요가 없습니다.

다음은 enum 클래스의 생성자를 이용한 예제입니다.

public enum Planet {
    MERCURY (3.303e+23, 2.4397e6),
    VENUS   (4.869e+24, 6.0518e6),
    EARTH   (5.976e+24, 6.37814e6),
    MARS    (6.421e+23, 3.3972e6),
    JUPITER (1.9e+27,   7.1492e7),
    SATURN  (5.688e+26, 6.0268e7),
    URANUS  (8.686e+25, 2.5559e7),
    NEPTUNE (1.024e+26, 2.4746e7);

    private final double mass;   // in kilograms
    private final double radius; // in meters
    
    Planet(double mass, double radius) {
        this.mass = mass;
        this.radius = radius;
    }
    private double mass() { return mass; }
    private double radius() { return radius; }

    // universal gravitational constant  (m3 kg-1 s-2)
    public static final double G = 6.67300E-11;

    double surfaceGravity() {
        return G * mass / (radius * radius);
    }
    double surfaceWeight(double otherMass) {
        return otherMass * surfaceGravity();
    }
    // main 
    public static void main(String[] args) {
        if (args.length != 1) {
            System.err.println("Usage: java Planet <earth_weight>");
            System.exit(-1);
        }
        double earthWeight = Double.parseDouble(args[0]);
        double mass = earthWeight/EARTH.surfaceGravity();
        for (Planet p : Planet.values())
           System.out.printf("Your weight on %s is %f%n",
                             p, p.surfaceWeight(mass));
    }
}

// expected output
$ java Planet 175
Your weight on MERCURY is 66.107583
Your weight on VENUS is 158.374842
Your weight on EARTH is 175.000000
Your weight on MARS is 66.279007
Your weight on JUPITER is 442.847567
Your weight on SATURN is 186.552719
Your weight on URANUS is 158.397260
Your weight on NEPTUNE is 199.207413

2. enum이 제공하는 메소드

1. static <T extends Enum> valueOf​(Class enumType, String name)

지정한 enum type의 enum 상수를 반환합니다.

  
import java.lang.*;

// enum showing Mobile prices
enum Mobile {
   Samsung(400), Nokia(250),Motorola(325);
  
   int price;
   Mobile(int p) {
      price = p;
   }
   int showPrice() {
      return price;
   } 
}

public class EnumDemo {
   
   public static void main(String args[]) {
   
      System.out.println("CellPhone List:");
      for(Mobile m : Mobile.values()) { 
         System.out.println(m + " costs " + m.showPrice() + " dollars");
      }

      Mobile ret;
      ret = Mobile.valueOf("Samsung"); 
      System.out.println("Selected : " + ret);                              
   }
}
  
// expected output
CellPhone List:
Samsung costs 400 dollars
Nokia costs 250 dollars
Motorola costs 325 dollars
Selected : Samsung  

2. static T[] values()

values() 메서드를 사용하여 열거형 내에 있는 모든 값을 반환할 수 있습니다.

enum Color { 
    RED, GREEN, BLUE; 
} 
  
public class Test { 
    public static void main(String[] args) { 
        Color arr[] = Color.values(); 
  
        for (Color col : arr) { 
            System.out.println(col + " at index "
                             + col.ordinal()); 
        } 
  
    } 
}
  
// expected output
RED at index 0
GREEN at index 1
BLUE at index 2  

3. final int ordinal()

enum 상수의 순서를 반환합니다. 초기 상수는 0부터 시작합니다.

EnumSet 및 EnumMap과 같은 정교한 Enum 기반 데이터 구조에서 사용하도록 설계되었습니다.

enum Color { 
    RED, GREEN, BLUE; 
} 
  
public class Test { 
    public static void main(String[] args) { 
        Color arr[] = Color.values(); 
  
        for (Color col : arr) { 
            System.out.println(col + " at index "
                             + col.ordinal()); 
        } 
  
    } 
}
  
// expected output
RED at index 0
GREEN at index 1
BLUE at index 2  

3. java.lang.Enum

java.lang.enum은 모든 enum 타입의 공통 베이스 클래스 입니다.

enum 타입은 컬렉션인 EnumSet과 EnumMap을 이용해서 사용할 수 있습니다.

다음은 java.lang 패키지에 있는 Enum 추상 클래스입니다.

public abstract class Enum<E extends Enum<E>>
      implements Comparable<E>, Serializable {

  // enum constant의 이름을 말합니다. 이름을 호출하기 위해서는 toString() 메소드를 통해 호출할 수 있습니다.
  private final String name;

  // enum constant의 이름을 호출하는 메소드 입니다. toString() 대신해서 사용할 수 있지만 프로그래머에게 익숙한 toString()을 사용하는걸 추천합니다.
  public final String name() {
      return name;
  }

  // enum constant의 순서를 말합니다. 처음 초기화는 0부터 시작하며 이 필드를 사용할 일은 enumSet과 enumMap을 사용할 때 사용됩니다.
  private final int ordinal

  // ordinal을 호출하는 메소드 입니다. 
  public final int ordinal() {
      return ordinal;
  }

  // enum 클래스에 있는 유일한 생성자 입니다. 접근제어자가 protected로 되어 있으므로 프로그래머는 이 메소드를 호출할 수 없습니다. 이 메소드는 컴파일러가 enum을 선언할 때 알아서 호출해주는 메소드 입니다. 
  protected Enum(String name, int ordinal) {
      this.name = name;
      this.ordinal = ordinal;
  }
}

4. EnumSet

Enum 타입을 사용하기 위한 Set implementation 입니다. enum에 있는 모든 요소들은 싱글 타입의 enum이어야 합니다.

이 EnumSet은 내부적으로 매우 작고 효율적인 bit vectors를 사용합니다. 그러므로 이 클래스의 공간 및 시간 성능은 굉장히 우수합니다.

EnumSet의 Iterator는 weakly consistent이므로 ConcurrentModificationException 예외를 던지지 않습니다.

EnumSet에 Null 요소는 허용되지 않습니다. Null을 넣으면 NullPointerException이 발생합니다.

대부분의 컬렉션 처럼 EnumSet은 not synchronized이므로 여러 스레드에서 엑세스 가능합니다. 그러므로 한 스레드가 Set을 수정하는 경우 해당 스레드는 동기화 되어야 합니다. 이를 위해 Collections.synchronizedSet(java.util.Set)를 통해서 가능합니다.

EnumSet Methods

1. static <E extends Enum> EnumSet allOf (Class elementType)

지정된 elementType에 있는 모든 요소를 포함하는 EnumSet을 리턴합니다.

enum GFG { 
  Welcome, 
  To, 
  The, 
  World, 
  of, 
  Geeks 
}; 

public class Enum_Set_Demo { 

  public static void main(String[] args) 
  { 
      EnumSet<GFG> e_set = null; 

      System.out.println(e_set); 

      e_set = EnumSet.allOf(GFG.class); 

      System.out.println("The updated set is:" + e_set); 
  } 
}
// expected output  
null
The updated set is:[Welcome, To, The, World, of, Geeks]  

2. static <E extends Enum> EnumSet complementOf (EnumSet s)

처음에 지정한 enumSet에 포함되지 않는 나머지 enum 타입 요소들을 EnumSet으로 리턴합니다.

import java.util.*; 

enum GFG { 
  Welcome, 
  To, 
  The, 
  World, 
  of, 
  Geeks 
} 
; 

public class Enum_Set_Demo { 

  public static void main(String[] args) 
  { 

      EnumSet<GFG> e_set = EnumSet.of(GFG.To, GFG.Welcome, 
                                      GFG.Geeks); 

      System.out.println("Initial set: " + e_set); 

      EnumSet<GFG> final_set = EnumSet.complementOf(e_set); 

      System.out.println("The updated set is:" + final_set); 
  } 
} 
// epxcted output
Initial set: [Welcome, To, Geeks]
The updated set is:[The, World, of]

3. static <E extends Enum> EnumSet copyOf (Collection c), copyOf (EnumSet s)

지정한 컬렉션에서 초기화된 EnumSet을 만들거나 지정한 enumSet에서 처음에 들어가 있는 동일한 요소를 포함한 EnumSet을 만드는 메소드 입니다.

// copyOf (Collection<E> c) 예제입니다. 

enum GFG { 
  Welcome, 
  To, 
  The, 
  World, 
  of, 
  Geeks 
} 
; 

public class Enum_Set_Demo { 

  public static void main(String[] args) 
  { 

      Collection<GFG> collect = new ArrayList<GFG>(); 

      collect.add(GFG.Welcome); 
      collect.add(GFG.World); 
      collect.add(GFG.Geeks); 

      System.out.println("The collection is: " + collect); 

      EnumSet<GFG> e_set = EnumSet.copyOf(collect); 

      System.out.println("The enum set is:" + e_set); 
  } 
}

// expected output
The collection is: [Welcome, World, Geeks]
The enum set is:[Welcome, World, Geeks]
// copyOf (EnumSet<E> s) 예제입니다. 

enum CARS { 
  RANGE_ROVER, 
  MUSTANG, 
  CAMARO, 
  AUDI, 
  BMW 
} 
; 

public class Enum_Set_Demo { 

  public static void main(String[] args) 
  { 

      EnumSet<CARS> e_set = EnumSet.allOf(CARS.class);         

      System.out.println("Initial set is: " + e_set); 

      EnumSet<CARS> new_set = EnumSet.copyOf(e_set); 

      System.out.println("The new set is: " + new_set); 
  } 
} 

4. static <E extends Enum> EnumSet noneOf (Class elementType)

지정한 elementType을 사용하여 빈 enumSet을 만듭니다.

enum GFG { 
  Welcome, 
  To, 
  The, 
  World, 
  of, 
  Geeks 
} 
; 

public class Enum_Set_Demo { 

  public static void main(String[] args) 
  { 

      EnumSet<GFG> e_set = EnumSet.allOf(GFG.class); 

      System.out.println("The first set is: " + e_set); 

      EnumSet<GFG> other_set = EnumSet.noneOf(GFG.class); 

      System.out.println("The other set is: " + other_set); 
  } 
}
// expected output
The first set is: [Welcome, To, The, World, of, Geeks]
The other set is: []

5. static <E extends Enum> EnumSet of (E e), of (E e1, E e2), of (E first, E... rest)

처음에 지정한 요소를 포함하는 enumSet을 만듭니다. 넣고 싶은만큼 넣을 수 있습니다.

enum GFG { 
  Welcome, 
  To, 
  The, 
  World, 
  of, 
  Geeks 
} 
; 

public class Enum_Set_Demo { 

  public static void main(String[] args) 
  { 

      EnumSet<GFG> e_set; 

      e_set = EnumSet.of(GFG.The, GFG.Geeks); 

      System.out.println("The enum set is: " + e_set); 

      e_set = EnumSet.of(GFG.The, GFG.Geeks, GFG.Welcome); 

      System.out.println("The enum set is: " + e_set); 

      e_set = EnumSet.of(GFG.Geeks, GFG.Welcome, 
                         GFG.of, GFG.World); 

      System.out.println("The enum set is: " + e_set); 

      e_set = EnumSet.of(GFG.Welcome, GFG.To, GFG.The, 
                         GFG.of, GFG.World, GFG.Geeks); 

      System.out.println("The enum set is: " + e_set); 
  } 
}

// expected output
The enum set is: [The, Geeks]
The enum set is: [Welcome, The, Geeks]
The enum set is: [Welcome, World, of, Geeks]
The enum set is: [Welcome, To, The, World, of, Geeks]

6. static <E extends Enum> EnumSet range (E from, E to)

처음에 지정된 두 끝점에서 정의된 범위의 모든 요소를 포함하는 enumSet을 만듭니다.

enum GFG { 
  Welcome, 
  To, 
  The, 
  World, 
  of, 
  Geeks 
} 
; 

public class Enum_Set_Demo { 

  public static void main(String[] args) 
  { 

      EnumSet<GFG> e_set; 

      e_set = EnumSet.range(GFG.The, GFG.Geeks); 

      System.out.println("The enum set is: " + e_set); 
  } 
} 
profile
좋은 습관을 가지고 싶은 평범한 개발자입니다.

0개의 댓글