[JDK 9] Immutable Collection 생성하기

2022. 5. 6. 11:51Java/Basic

반응형
  1. Immutable Collection?
  2. JDK 9 버전 이전
    1. moditable List 생성 예 - Arrays.asList
    2. immutableList List 생성 예 - Collections.unmodifiableList
    3. immutableList Set 생성 예 - Collections.unmodifiableSet
  3. JDK 9 버전 이후
    1. List
      1. List.of
      2. List.copyOf
    2. Set
      1. Set.of
      2. Set.copyOf
    3. Map
      1. Map.of
      2. Map.copyOf
      3. Map.ofEntries

1. Immutable Collection?

Immutable은 수정할 수 없는(=불변)을 뜻하는 말로, Immutable Collection을 다른 말로 표현하자면 읽기전용 컬랙션을 의미합니다.

어떤 데이터를 이용하고자 할때, 의도치 않은 변경이 일어나지 않아야할 때 이용하면 좋습니다.

Java에서는 불변 컬랙션을 정의하는 방법을 제공하고 있으나 Collection Literal을 제공하고 있지 않아서 List나 Set, Map을 초기화하는것이 불편했습니다.

물론, Collection Literal은 제공되지 않았으나 아래와 같은 형태로 불변 컬랙션을 정의하는것은 가능했으나 보다시피 코드도 길고 가독성이 떨어집니다.

Set<String> set = Collections.unmodifiableSet(new HashSet<>(Arrays.asList("apple", "banana", "melon")));
Set<String> set = Collections.unmodifiableSet(new HashSet<String>() {{
    add("aapple"); add("banana"); add("melon");
}});

이번 시간에는 JDK 9 이전 버전에서 불변 컬랙션을 초기화하는 방법과, JDK 9에서 새로 추가된 정의방법을 알아보도록 합니다.


2. JDK 9 버전 이전

2.1. moditable List 생성 예 - Arrays.asList

public static <T> List<T> asList(T... a)

Arrays.asList는 사이즈가 고정된 리스트를 생성하는 정적메서드 입니다.
사이즈는 변경은 불가능하나, 각 요소를 수정은 할 수 있습니다. (modifiable)
사이즈 수정이 불가능하기 때문에 요소 추가 및 제거는 안됩니다.

추가 또는 제거 시도시 UnsupportedOperationException 발생됩니다.

List<String> mutableList = Arrays.asList("apple", "banana");
mutableList.set(0, "melon");   // 수정은 가능
// mutableList.add("melon"); // 추가는 불가능
// mutableList.remove(1);       // 요소 제거도 불가능

그러나, 만약 수정이 아예불가능한 리스트를 정의하고 싶었다면 Arrays.asList 를 이용하여 정의한 위의 코드는 부적절합니다.


2.2. immutable List 생성 예 - Collections.unmodifiableList

public static <T> List<T> unmodifiableList(List<? extends T> list)

Collections.unmodifiableList 은 리스트를 불변 리스트로 복제하는 정적 메서드입니다.
요소 추가 및 삭제 뿐만 아니라, 수정도 불가능합니다.

List<String> mutableList = new ArrayList<>();
mutableList.add("apple");
mutableList.add("banana");

List<String> immutableList = Collections.unmodifiableList(mutableList);
// immutableList.set(0, "melon");   // 수정, 추가, 삭제 모두 불가능
// immutableList.add("melon");
// immutableList.remove(1);

다만, List를 인자값으로 받기 때문에 위와 같이 복제하고 싶은 리스트가 있다면 무난하겠지만, 바로 초기화해서 생성하고자 하면 코드가 다소 복잡해집니다.

List<String> immutableList = Collections.unmodifiableList(Arrays.asList("apple", "banana"));

2.3. immutableList Set 생성 예 - Collections.unmodifiableSet

public static <T> Set<T> unmodifiableSet(Set<? extends T> s)

불변 Set을 만드는것은 불변 List를 만드는 것보다 조금 더 불편합니다.
Arrays.asList로 리스트를 만든것을 HashSet 생성자에 담은 후, Collections.unmodifiableSet에 담습니다.

Set<Integer> immutableSet = Collections.unmodifiableSet(new HashSet<>(Arrays.asList(1, 10, 5)));

3. JDK 9 버전 이후

JDK 9 에서는 불변 컬랙션을 간편하게 생성할 수 있는 static factory Method가 추가되었습니다.

JEP 269: Convenience Factory Methods for Collections
Release 9


3.1. List

3.1.1. List.of

static <E> List<E> of()
static <E> List<E> of(E e1)
static <E> List<E> of(E e1, E e2)
...
static <E> List<E> of(E e1, E e2, E e3, E e4, E e5, E e6, E e7, E e8, E e9, E e10)
static <E> List<E> of(E... elements)

List.of 정적 팩토리 메서드는 수정할 수 없는 리스트를 편리하게 생성할 수 있게 해줍니다.
또, 리스트를 초기화 할 때 null 값의 요소를 설정하는 것을 허용하지 않습니다.

List<String> immutableList = List.of("apple", "banana", "melon");
// List<String> immutableList = List.of("apple", "banana", "melon", null); // null 요소 설정시 에러 발생

3.1.2. List.copyOf

static <E> List<E> copyOf(Collection<? extends E> coll)

List.copyOf 정적 팩토리 메서드는 컬랙션을 이용하여 불변 리스트를 생성합니다.
List.of과 마찬가지로 리스트를 초기화 할 때 null 값의 요소를 설정하는 것을 허용하지 않습니다.

List<String> list = Arrays.asList("red", "green", "red");
List<String> immutableList2 = List.copyOf(list);
System.out.println(immutableList2);
[red, green, red]

3.2. Set

3.2.1. Set.of

static <E> Set<E> of()
static <E> Set<E> of(E e1)
static <E> Set<E> of(E e1, E e2)
...
static <E> Set<E> of(E e1, E e2, E e3, E e4, E e5, E e6, E e7, E e8, E e9, E e10)
static <E> Set<E> of(E... elements)

Set.of 정적 팩토리 메서드는 수정할 수 없는 Set을 편리하게 생성할 수 있게 해줍니다.
null 값은 허용하지 않으며, 중복되는 값도 허용하지 않습니다.

Set<Integer> immutableSet = Set.of(8, 10, 88)
// Set<Integer> immutableSet = Set.of(8, 10, 88, 8); // 중복 요소 설정 시 에러 발생

3.2.2. Set.copyOf

static <E> Set<E> copyOf(Collection<? extends E> coll)

Set.copyOf 정적 팩토리 메서드는 컬랙션을 이용하여 불변 Set를 생성합니다.
컬랙션 내의 각 요소는 null은 허용하지 않지만, 중복된 값이 있어도 에러를 발생시키지 않습니다.

List<String> list = Arrays.asList("red", "green", "red");
Set<String> immutableSet2 = Set.copyOf(list);
System.out.println(immutableSet2);
[red, green]

3.3. Map

3.3.1. Map.of

static <K, V> Map<K, V> of()
static <K, V> Map<K, V> of(K k1, V v1)
static <K, V> Map<K, V> of(K k1, V v1, K k2, V v2)
...
static <K, V> Map<K, V> of(K k1, V v1, K k2, V v2, K k3, V v3, K k4, V v4, K k5, V v5,
                               K k6, V v6, K k7, V v7, K k8, V v8, K k9, V v9, K k10, V v10)

Key, Value를 인자에 번갈아 설정하는 방식으로 불변 Map을 정의하는 Map.of 정적 팩토리 메서드입니다.
Key나 Value에 null값을 허용하지 않습니다.
중복된 Key값을 설정하는 것도 허용하지 않습니다.

Map<String, Integer> immutableMap = Map.of("coco", 28, "lily", 34);
// Map<String, Integer> immutableMap1 = Map.of("coco", 28, "lily", 34, "rora", null); // Value값에 null을 허용하지 않습니다.
// Map<String, Integer> immutableMap1 = Map.of("coco", 28, "lily", 34, "coco", 4);  // 중복된 Key값은 허용하지 않습니다.
System.out.println(immutableMap);
{coco=28, lily=34}

3.3.2. Map.copyOf

static <K, V> Map<K, V> copyOf(Map<? extends K, ? extends V> map)

Map.copyOf는 Map을 입력받아 불변 Map으로 복제하는 정적 팩토리 메서드입니다.
입력받을 인자값인 map과 map의 요소는 null값을 허용하지 않습니다.

Map<Integer, String> map = new HashMap<>();
map.put(1, "red");
map.put(2, "blue");
// map.put(3, null);     // Map.copyOf 에 넣을 경우 에러 발생

Map<Integer, String> immutableMap2 = Map.copyOf(map);
System.out.println(immutableMap2);
{1=red, 2=blue}

3.3.3. Map.ofEntries

static <K, V> Map<K, V> ofEntries(Entry<? extends K, ? extends V>... entries)

Map.entry 를 인자로 받아 불변 Map을 만드는 정적 팩토리 메서드입니다.
Key는 중복으로 들어갈 수 없고, 마찬가지로 null값은 허용하지 않습니다.

Map<String, Integer> immutableMap3 = Map.ofEntries(Map.entry("coco", 28), Map.entry("lily", 34));
System.out.println(immutableMap3);
{lily=34, coco=28}

※ 관련 Gist


++ References


++

  • Java에서 불변 컬랙션 생성하기
  • static factory method를 이용한 immutable Collection 생성하기
728x90
반응형