삽질기록 #3 일급 컬렉션, 자바 Enum

    (2022.02.22)

    오늘 썼던 코드들 중 제대로 모르고 썼던 개념들을 위주로 정리해 본다.

     

    일급 컬렉션(First Class Collection)

    향로님의 블로그에 잘 정리가 되어 있는데, 기본적으로 Map이나 List같은 Collection을 클래스로 Wrapping하고, 해당 클래스 외에는 다른 멤버변수를 두지 않는 것을 의미한다. 그냥 List<T>를 쓰면 계속해서 List에 값이 추가될 수 있다는 단점이 있다. 이는 저번 삽질기록 #1에서 보았던 List 멤버 변수의 값 변경 문제와도 맞닿아 있다. 그럴 때 해당 collection 외의 다른 멤버 변수는 갖지 않는 클래스로 collection을 wrapping하면, 클래스 자체를 일종의 자료구조처럼 쓰면서 값의 불변성을 보장받을 수 있다.

    public class Scores {
    	private List<Integer> scoreList;
        
        public Scores(List<Integer> scoreList) {
        	this.scoreList = scoreList;
        }
    }

    이런 식으로 playerList를 private으로 매핑하면 Scores는 처음에 한 번 생성된 후에는, 그 안에 들어있는 List의 값을 외부에서 변경하는 게 불가능해진다. 즉 불변성이 보장된다는 얘기다. 또한 생성자에서 여러 조건을 달아서 자료구조의 형식을 지정하는 것도 가능하다. (ex. 5 이상의 값만 가져야 한다든지...)

     

    이런 식으로 관리가 편해지는 장점이 있지만, 오늘 작업 과정에서도 이런 collection도 내부 값을 사용해야 할 경우가 있을 텐데, getter같은 메서드는 어떤 식으로 만들어야 하는지가 고민이 되었다. 향로님 글에서는 이렇게 Integer 리스트 등인 경우에는 getSum() 같은 형태로 정수만 넘겨주는 메서드를 만드는 것으로 값을 보호했다. 그런데 List의 형태로 전체 값이 필요할 수도 있잖아? 그래서 찾아보니 이런 경우에 Collections.unmodifiableList()를 사용한다는 블로그 글을 볼 수 있었다. 일급 컬렉션의 핵심이 'collection의 불변성 유지'라는 점을 생각해 보면, unmodifiableLIst()는 결국 원본 collection의 불변성은 해치지 않는 것이기 때문에 일급 컬렉션의 특성을 해치는 것은 아니라는 생각이 들었다.

     

     

    자바 Enum

    지금까지 Enum은 '정해진 범위 안에서의 상수값 모임' 같은 느낌으로만 사용했었다. 그런데 오늘 조금 더 깊게 써 보니 Enum은 정말 '클래스'의 일종이라 꽤 다양한 기능을 가지고 있다. 특히 한 타입에 2개 이상의 값을 할당할 수 있는 건 처음 알았다. 조금 더 정리해 본다.

     

    Enum은 결국 내부적으로는 public static final인 상수들이다. 이런 상수들을 모아서 클래스를 만든 거라고 보면 된다. 그래서 메서드도 쓸 수 있다! Enum은 모두 java.lang.Enum 클래스를 상속하기 때문에 이 부모 클래스의 메서드들을 사용할 수 있는데 대표적인 것들은 아래와 같다.

    1. values(): enum 내부의 모든 값을 리턴한다. 문서에 없어서 찾아보니 사실 이건 Enum 클래스나 자바 라이브러리에 있는 표준 메서드는 아니고, 컴파일러가 임의로 추가해 준 메서드라고. (출처)
    2. toString(): 해당 enum 상수의 이름을 string으로 변환해 넘겨준다.
    3. valueOf(): 해당 스트링에 맞는 enum 상수가 있을 경우 리턴해준다.
    4. ordinal(): Enum 클래스 내에서 해당 enum 상수의 인덱스 넘버를 리턴해준다.

    - 기본적으로 가지고 있는 String 상수값 외에, 추가로 string 값을 가질 수 있는데, 이 경우에는 해당 값에 접근하기 위한 private 변수를 선언해줘야 한다. 앞서 말했듯 Enum은 클래스라서 메서드도 가질 수 있다. 대표적으로 그 enum 값의 변수에 접근할 수 있는 getter() 메서드도 만들 수 있다. 무슨 의미냐면...

     

    Enum Nation
    {
        KOREA("SEOUL"), USA("WASHINGTON"), NORWAY("OSLO");
        
        private String capital;
        
        public String getCapital()
        {
        	return this.capital;
        }
        
        private Nation(String capital)
        {
        	this.capital = capital;
        }
    }
    
    public class Example
    {
        public static void main(String args[])
        {
        	for (Nation nation : Nation.values()
            {
                System.out.println("name: " + nation.name() + ", capital: " + nation.getCapital());
                // name: KOREA, capital: SEOUL
                // name: USA, capital: WASHINGTON
                // name: NORWAY, capital: OSLO
            }
        }
    }

    이런 식으로 각 enum 상수마다 capital이라는 private String 변수를 따로 가지고, getCapital() 메서드를 통해서 해당 변수값을 가져올 수 있다는 의미이다. 여기서 private으로 정의된 생성자는 paramiterized constructor라는 이름으로 불리던데, 아직 정확한 의미와 역할은 이해하지 못했다. 내부적으로 enum이 만들어질 때 이 private 생성자를 호출하는 방식이라는 것 같기는 한데, 더 자세히는 추후에 정리해 보기.

     

     

    더 공부할 것들

    - Stream 각종 메서드들 조금 더 확실히!: Stream 너무 구글링 주도 개발로 연명해서 쓰고 있다. 주요 메서드들은 내 힘으로 쓸 수 있을 때까지 익혀보자!

    - Enum 추가 공부. Enum을 Map처럼 사용할 수 있게 해주는 EnumMap이라는 것도 있다고. 조금 더 깊게 공부해서 Enum 좀 편하게 써보자!

     

    댓글