SSAFY-Book-Study / modern-java-in-action

모던 자바 인 액션 북스터디입니다.
1 stars 10 forks source link

3 Weeks - [map.of vs map.ofentries] #50

Open Hot-ttu opened 1 year ago

Hot-ttu commented 1 year ago

문제

Map.of와 Map.ofentries의 차이가 궁금합니다.

contents - 세부 내용

책 에서 맵 초기화 방법으로 Map.of와 Map.ofEntries 두 가지 방법을 소개하여 주었는데, 키와 값 쌍의 개수에 따라서만 두 메서드 사용의 차이를 두었는데 다른 차이점도 궁금합니다.

참고

책 p.279

leetaggg commented 1 year ago

Map.of()와 Map.ofEntries()는 자바9에서 추가된 Map을 생성하는 팩토리 메서드이며, 두 메서드 모두 불변 컬렉션을 만듭니다. 두 메서드는 2가지 차이점이 있습니다.

1. 인자 형태의 차이

Map.of()는 인자를 Map.of(Key1, Value1, Key2, Value2, ...)로 키와 값을 번갈아가며 쌍으로 받습니다.

Map.ofEntries는 Entry를 객체를 인자로 받아 생성되며, Map.entry(Key, Value)를 통해 생성할 수 있습니다.

Map<String, Integer> map1 = Map.of("Key1", 1, "Key2", 2, "Key3", 3);

Map<String, Integer> map2 = Map.ofEntries(Map.entry("Key1", 1),
                                                    Map.entry("Key2", 2),
                                                    Map.entry("Key3", 3));

2. 맵의 크기

Map.of()는 받을 수 있는 인자를 10개로 제한되어 있습니다.

Map.ofEntries()는 받을 수 있는 인자가 제한되어있지 않습니다.

Map<String, Integer> map1 = Map.of("Key1", 1, "Key2", 2, "Key3", 3, 
                "Key4", 4, "Key5", 5, "Key6", 6, "Key7", 7, "Key8", 8, 
                "Key9", 9, "Key10", 10, "Key11", 11); // 오버로딩할 적절한 메서드를 찾을 수 없습니다.

Map<String, Integer> map2 = Map.ofEntries(Map.entry("Key1", 1),
                    Map.entry("Key2", 2),
                    Map.entry("Key3", 3),
                    Map.entry("Key4", 4),
                    Map.entry("Key5", 5),
                    Map.entry("Key6", 6),
                    Map.entry("Key7", 7),
                    Map.entry("Key8", 8),
                    Map.entry("Key9", 9),
                    Map.entry("Key10", 10),
                    Map.entry("Key11", 11));

그 이유는 Map 인터페이스의 of() 메서드는 인자의 개수에 맞춰 오버로딩이 되어있으며, 인자의 개수가 10개까지 오버로딩이 되어있기 때문입니다.

// 인자의 개수가 10개까지만 오버로딩 되어있음
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) {
        return new ImmutableCollections.MapN<>(k1, v1, k2, v2, k3, v3, k4, v4, k5, v5,
                                               k6, v6, k7, v7, k8, v8, k9, v9, k10, v10);
    }

Map.ofEntries()는 가변 인수를 매개변수로 하기 때문에 인자의 갯수의 제한을 받지 않습니다.

// 가변인자
static <K, V> Map<K, V> ofEntries(Entry<? extends K, ? extends V>... entries) {
        if (entries.length == 0) { // implicit null check of entries array
            @SuppressWarnings("unchecked")
            var map = (Map<K,V>) ImmutableCollections.EMPTY_MAP;
            return map;
        } else if (entries.length == 1) {
            // implicit null check of the array slot
            return new ImmutableCollections.Map1<>(entries[0].getKey(),
                    entries[0].getValue());
        } else {
            Object[] kva = new Object[entries.length << 1];
            int a = 0;
            for (Entry<? extends K, ? extends V> entry : entries) {
                // implicit null checks of each array slot
                kva[a++] = entry.getKey();
                kva[a++] = entry.getValue();
            }
            return new ImmutableCollections.MapN<>(kva);
        }
    }

Map.of VS Map.ofEntries

그렇다면 두 메서드를 어느 상황에 사용하여야 할까?

Map.ofEntries는 가변 인수를 추가 배열로 할당하여 리스트로 감싸기 때문에 배열을 할당하는 비용과 나중에 가비지 컬렉션을 하는 비용이 있습니다. 하지만 Map.of는 고정된 인수를 받기 때문에 가변 인수에 비해 추가 비용을 사용하지 않는다는 장점이 있습니다. 따라서 10개 이하의 키-값의 경우는 Map.of를 사용하고, 10개를 넘는 키-값의 경우에는 Map.ofEntries를 사용하여야 합니다.