Соображения производительности для набора ключей() и entrySet () карты
все,
может кто-нибудь, пожалуйста, дайте мне знать, какие именно проблемы с производительностью между 2? Сайт : CodeRanch предоставляет краткий обзор внутренних вызовов, которые будут необходимы при использовании keySet() и get(). Но было бы здорово, если бы кто-нибудь мог предоставить точные сведения о потоке, когда используются методы keySet() и get (). Это поможет мне лучше понять проблемы с производительностью.
3 ответа:
прежде всего, это полностью зависит от того, какой тип карты вы используете. Но поскольку поток JavaRanch говорит о HashMap, я предполагаю, что это реализация, о которой вы говорите. И давайте также предположим, что вы говорите о стандартной реализации API от Sun/Oracle.
во-вторых, если вы беспокоитесь о производительности при итерации по хэш-карту, я предлагаю вам посмотреть
LinkedHashMap
. Из документов:итерация по коллекции-представления LinkedHashMap требует времени, пропорционального размеру карты, независимо от ее емкости. Итерация по хэш-карте, вероятно, будет более дорогой, требуя времени, пропорционального его емкости.
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.набор ключей() и .получить()
здесь вам сначала нужно получить набор ключей. Это занимает время, пропорциональное емкости карты (в отличие от в размере для LinkedHashMap). После того, как это будет сделано, вы звоните
get()
один раз для каждого ключа. Конечно, в среднем случае, с хорошим хэш-кодом-реализация этого занимает постоянное время. Однако, это неизбежно потребует много.hashCode
и.equals
звонки, которые, очевидно, займет больше времени, чем просто делатьentry.value()
звонок.
наиболее распространенный случай, когда использование entrySet предпочтительнее набора ключей, - это когда вы перебираете все пары ключ/значение на карте.
это более эффективно:
for (Map.Entry entry : map.entrySet()) { Object key = entry.getKey(); Object value = entry.getValue(); }
чем:
for (Object key : map.keySet()) { Object value = map.get(key); }
потому что во втором случае, для каждого ключа в ключей в
map.get()
вызывается метод, который - в случае HashMap-требует, чтобыhashCode()
иequals()
методы ключевого объекта должны быть оценены для того, чтобы найти соответствующее значение*. В первый случай, когда лишняя работа исключается.Edit: это еще хуже, если вы рассматриваете TreeMap, где вызов get-O(log2(n)), т. е. компаратору для will может потребоваться запустить log2(n) раз (n = размер карты), прежде чем найти соответствующее значение.
*некоторые реализации карт имеют внутреннюю оптимизацию, которая проверяет идентичность объектов перед
hashCode()
иequals()
называются.
вот ссылка на статью сравнение производительности
entrySet()
,keySet()
иvalues()
, и советы относительно того, когда использовать каждый подход.очевидно, что использование
keySet()
быстрее (кроме того, что более удобным), чемentrySet()
до тех пор, пока вам не нужноMap.get()
значения.