IT TIP

Map의 keySet () 및 entrySet ()에 대한 성능 고려 사항

itqueen 2020. 10. 23. 19:47
반응형

Map의 keySet () 및 entrySet ()에 대한 성능 고려 사항


모두,

누구든지 2 사이의 성능 문제가 무엇인지 정확히 알려 주실 수 있습니까? 사이트 : CodeRanch 는 keySet () 및 get ()을 사용할 때 필요한 내부 호출에 대한 간략한 개요를 제공합니다. 그러나 keySet () 및 get () 메서드를 사용할 때 누구든지 흐름에 대한 정확한 세부 정보를 제공 할 수 있다면 좋을 것입니다. 이것은 성능 문제를 더 잘 이해하는 데 도움이 될 것입니다.


우선, 이것은 전적으로 사용중인지도 유형에 따라 다릅니다. 그러나 JavaRanch 스레드가 HashMap에 대해 이야기하기 때문에 이것이 당신이 언급하는 구현이라고 가정하겠습니다. 또한 Sun / Oracle의 표준 API 구현에 대해 이야기하고 있다고 가정 해 보겠습니다.

둘째, 해시 맵을 반복 할 때 성능이 염려된다면 LinkedHashMap. 문서에서 :

LinkedHashMap의 컬렉션 뷰를 반복하려면 용량에 관계없이 맵 크기에 비례하는 시간이 필요합니다. HashMap을 통한 반복은 비용이 더 많이 들고 용량에 비례하는 시간이 필요합니다.

HashMap.entrySet ()

이 구현의 소스 코드를 사용할 수 있습니다. 구현은 기본적으로 새로운 HashMap.EntrySet. 다음과 같은 클래스 :

private final class EntrySet extends AbstractSet<Map.Entry<K,V>> {
    public Iterator<Map.Entry<K,V>> iterator() {
        return newEntryIterator(); // returns a HashIterator...
    }
    // ...
}

그리고 HashIterator외모가 좋아

private abstract class HashIterator<E> implements Iterator<E> {
    Entry<K,V> next;    // next entry to return
    int expectedModCount;   // For fast-fail
    int index;      // current slot
    Entry<K,V> current; // current entry

    HashIterator() {
        expectedModCount = modCount;
        if (size > 0) { // advance to first entry
            Entry[] t = table;
            while (index < t.length && (next = t[index++]) == null)
                ;
        }
    }

    final Entry<K,V> nextEntry() {
        if (modCount != expectedModCount)
            throw new ConcurrentModificationException();
        Entry<K,V> e = next;
        if (e == null)
            throw new NoSuchElementException();

        if ((next = e.next) == null) {
            Entry[] t = table;
            while (index < t.length && (next = t[index++]) == null)
                ;
        }
    current = e;
        return e;
    }

    // ...
}

그래서 당신은 그것을 가지고 있습니다 ... 그것은 entrySet을 반복 할 때 일어날 일을 지시하는 코드입니다. 맵 용량만큼 긴 전체 어레이를 안내합니다.

HashMap.keySet () 및 .get ()

Here you first need to get hold of the set of keys. This takes time proportional to the capacity of the map (as opposed to size for the LinkedHashMap). After this is done, you call get() once for each key. Sure, in the average case, with a good hashCode-implementation this takes constant time. However, it will inevitably require lots of .hashCode and .equals calls, which will obviously take more time than just doing a entry.value() call.


The most common case where using entrySet is preferable over keySet is when you are iterating through all of the key/value pairs in a Map.

This is more efficient:

for (Map.Entry entry : map.entrySet()) {
    Object key = entry.getKey();
    Object value = entry.getValue();
}

than:

for (Object key : map.keySet()) {
    Object value = map.get(key);
}

Because in the second case, for every key in the keySet the map.get() method is called, which - in the case of a HashMap - requires that the hashCode() and equals() methods of the key object be evaluated in order to find the associated value*. In the first case that extra work is eliminated.

Edit: This is even worse if you consider a TreeMap, where a call to get is O(log2(n)), i.e. the comparator for will may need to run log2(n) times (n = size of the Map) before finding the associated value.

*Some Map implementations have internal optimisations that check the objects' identity before the hashCode() and equals() are called.


Here is the link to an article comparing the performance of entrySet(), keySet() and values(), and advice regarding when to use each approach.

Apparently the use of keySet() is faster (besides being more convenient) than entrySet() as long as you don't need to Map.get() the values.

참고URL : https://stackoverflow.com/questions/3870064/performance-considerations-for-keyset-and-entryset-of-map

반응형