ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • [whiteship] 온라인스터디 - 11주차 과제 : Enum
    IT 발자취.../JAVA 2021. 1. 30. 23:37

    github.com/whiteship/live-study/issues/11

     

    11주차 과제: Enum · Issue #11 · whiteship/live-study

    목표 자바의 열거형에 대해 학습하세요. 학습할 것 (필수) enum 정의하는 방법 enum이 제공하는 메소드 (values()와 valueOf()) java.lang.Enum EnumSet 마감일시 2021년 1월 30일 토요일 오후 1시까지.

    github.com

    목표

    자바의 열거형에 대해 학습하세요.

    학습할 것 (필수)

    • enum 정의하는 방법
    • enum이 제공하는 메소드 (values()와 valueOf())
    • java.lang.Enum
    • EnumSet

    enum 정의하는 방법

    자바의 열거형 (enum)은 열거형이 갖는 값뿐만 아니라 타입까지 관리하기 때문에 보다 논리적인 오류를 줄일 수 있다.

    기존의 많은 언어들이 타입이 달라도 값이 같으면 조건식 결과가 참이었으나 자바의 '타입에 안전한 열거형 (typesafe enum)'에서는 실제 값이 같아도 타입이 다르면 조건식의 결과가 거짓이 된다. 

     

    enum 열거형이름 { 상수명1, 상수명2, ... }

    예시, 동서남북 4방향을 상수로 정의하는 열거형 Direction

    public enum Direction {
        EAST,
        SOUTH,
        WEST,
        NORTH;
    }

     

    java.lang.Enum - enum이 제공하는 메소드 (values()와 valueOf())

    모든 열거형의 조상은 java.lang.Enum 클래스이다.

    docs.oracle.com/javase/10/docs/api/java/lang/Enum.html

     

    Enum (Java SE 10 & JDK 10 )

    Returns the enum constant of the specified enum type with the specified name. The name must match exactly an identifier used to declare an enum constant in this type. (Extraneous whitespace characters are not permitted.) Note that for a particular enum typ

    docs.oracle.com

     

    타입 메서드 설명
    Class<E> getDeclaringClass() 열거형의 Class 객체를 반환한다.
    String name() 열거형 상수의 이름을 문자열로 반환한다.
    int ordinal() 열거형 상수가 정의된 순서를 반환한다. (0부터 시작)
    static <T extends Enum<T>> T valueof(Class<T> enumType, String name) 지정된 열거형에서 name과 일치하는 열거형 상수를 반환한다.

    컴파일러가 자동적으로 추가해주는 메서드

    static E values()
    static E valueOf(String name)

     

    아래는 valueof 메서드의 주석에서 얻어온 문장

    * All the constants of an enum type can be obtained by calling the implicit {@code public static T[] values()} method of that type.

     

    public static void main(String[] args) {
            System.out.printf("Direction EAST getDeclaringClass : %s \n", Direction.EAST.getDeclaringClass());
            System.out.printf("Direction EAST name : %s \n",Direction.EAST.name());
            System.out.printf("Direction EAST ordinal : %s \n",Direction.EAST.ordinal());
            // static method
            System.out.printf("Direction EAST valueOf (static) : %s \n",Direction.valueOf(Direction.class, "EAST"));
    
            // implicit methods
            // valueOf() - 상수의 이름으로 문자열 상수에 대한 참조를 얻을 수 있다.
            Direction d= Direction.valueOf("WEST");
            System.out.printf("Direction valueOf : %s ", d);  // WEST
            System.out.println(Direction.WEST==Direction.valueOf("WEST")); // TRUE
            // value()
            System.out.println("###############################################");
            System.out.println("##############Direction.values()###############");
            System.out.println("###############################################");
            Arrays.stream(Direction.values())
                    .forEach(direction -> System.out.println(direction.name()));
    }
    
    // Result
    Direction EAST getDeclaringClass : class com.gintire.pure.week11.Direction 
    Direction EAST name : EAST 
    Direction EAST ordinal : 0 
    Direction EAST valueOf (static) : EAST 
    Direction valueOf : WEST true
    ###############################################
    ##############Direction.values()###############
    ###############################################
    EAST
    SOUTH
    WEST
    NORTH

    EnumSet

    ## effective java - 규칙32. 비트 필드(bit field) 대신 EnumSet을 사용하라

    EnumSet은 특정한 enum 자료형의 값으로 구성된 집합을 효율적으로 표현할 수 있다.

    이 클래스는 Set 인터페이스를 구현하며, Set이 제공하는 풍부한 기능들을 그대로 제공할 뿐 아니라 형 안전성, 그리고 다른 Set 구현들과 같은 수준의 상호운용성도 제공한다.

    하지만 내부적으로는 비트 벡터 (bit vector)를 사용한다. enum 값 개수가 64 이하인 경우 EnumSet은 long 값 하나만 사용한다. 따라서 비트 필드에 필적하는 성능이 나온다. removeAll이나 retailAll 같은 일괄 연산도 비트 단위 산술 연산을 통해 구현한다. 

    더보기

    비트 열거형 상수

    public class Text {
        public static final int STYLE_BOLD = 1 << 0;    //1
        public static final int STYLE_ITALIC = 1 << 1;    //2
        public static final int STYLE_UNDERLINE = 1 << 2;    //4
        public static final int STYLE_STRIKETHROUGH = 1 << 3;    //8
    
        // 이 메서드의 인자는 STYLE_ 상수를 비트별 (bitwise) OR 한 값이거나 0,
        public void applyStyles (int styles) {
            //
        }
    }

    열거 자료형을 집합에 사용해야 한다고 해서 비트 필드로 표현하면 곤란하다. 

    EnumSet 클래스는 비트 필드 만큼 간결하고 성능도 우수할 뿐 아니라, enum 자료형의 여러 가지 장점을 전부 갖추고 있다.

    public class TestEmum {
        public enum Style {
            BOLD, ITALIC, UNDERLINE, STRIKETHROUGH
        }
        // 어떤 Set 객체도 인자로 전달할 수 있으나, EnumSet이 분명 최선
        // 인터페이스를 자료형으로 쓰는 것이 낫다
        public void applyStyles(Set<Style> styles) {}
    }
    text.applyStyles(EnumSet.of(TestEmum.Style.BOLD, TestEmum.Style.ITALIC));

    EnumMap

    public class Herb {
        enum Type {ANNUAL, PERENNIAL, BIENNIAL}
        final String name;
        final Type type;
    
        public Herb(String name, Type type) {
            this.name = name;
            this.type = type;
        }
    
        @Override
        public String toString() {
            return name;
        }
    }
    
    Herb[] garden = new Herb[3];
    garden[0] = new Herb("Basil", Herb.Type.ANNUAL);
    garden[1] = new Herb("Lovage", Herb.Type.PERENNIAL);
    garden[2] = new Herb("Angelica", Herb.Type.BIENNIAL);
    
    Map<Herb.Type, Set<Herb>> herbsByType = new EnumMap<Herb.Type, Set<Herb>>(Herb.Type.class);
    for(Herb.Type t : Herb.Type.values()) herbsByType.put(t, new HashSet<>());
    for(Herb h : garden) herbsByType.get(h.type).add(h);
    System.out.println(herbsByType);
    
    
    //result
    {ANNUAL=[Basil], PERENNIAL=[Lovage], BIENNIAL=[Angelica]}

    댓글

Designed by Gintire