すべて、
誰もが2の間のパフォーマンスの問題を正確に教えてもらえますか?サイト: CodeRanch は、keySet()およびget()を使用するときに必要になる内部呼び出しの概要を提供します。ただし、keySet()メソッドとget()メソッドを使用するときに、フローに関する正確な詳細を誰でも提供できれば素晴らしいことです。これは、パフォーマンスの問題をよりよく理解するのに役立ちます。
まず、これは使用しているマップのタイプに完全に依存します。しかし、JavaRanchスレッドはHashMapについて話しているため、それがあなたが参照している実装であると想定します。また、Sun/Oracleの標準API実装について話していると仮定しましょう。
第二に、ハッシュマップを反復処理する際のパフォーマンスが心配な場合は、 LinkedHashMap
をご覧になることをお勧めします。ドキュメントから:
LinkedHashMapのコレクションビューの反復には、容量に関係なく、マップのサイズに比例した時間が必要です。 HashMapでの反復はより高価である可能性が高く、その容量に比例した時間が必要です。
この実装のソースコードが利用可能です。実装は基本的に新しい_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を反復するときに何が起こるかを指示するコードです。マップの容量と同じ長さのアレイ全体をウォークスルーします。
ここでは、最初にキーのセットを取得する必要があります。これには、マップのcapacityに比例する時間がかかります(LinkedHashMapのsizeとは対照的)。これが完了したら、キーごとにget()
を1回呼び出します。確かに、平均的なケースでは、適切なhashCode実装では、これには一定の時間がかかります。ただし、必然的に多くの_.hashCode
_および_.equals
_呼び出しが必要になります。これは、明らかにentry.value()
呼び出しを行うよりも時間がかかります。
EntrySetの使用がkeySetよりも望ましい最も一般的なケースは、Map内のすべてのキー/値ペアを反復処理する場合です。
これはより効率的です。
for (Map.Entry entry : map.entrySet()) {
Object key = entry.getKey();
Object value = entry.getValue();
}
より:
for (Object key : map.keySet()) {
Object value = map.get(key);
}
2番目のケースでは、keySetのすべてのキーに対してmap.get()
メソッドが呼び出されます。これは、HashMapの場合、hashCode()
およびequals()
メソッドを必要とします関連付けられた値を見つけるためにキーオブジェクトが評価されます*。最初のケースでは、余分な作業がなくなります。
編集:これは、getの呼び出しがO(log2(n))であるTreeMapを検討する場合、さらに悪いです、つまり、コンパレータはlog2(n)回(n =マップのサイズ)を見つける前に実行する必要があります関連する値。
*一部のマップ実装には、hashCode()
およびequals()
が呼び出される前にオブジェクトのIDをチェックする内部最適化があります。
記事へのリンクですentrySet()
、keySet()
、values()
のパフォーマンスの比較、および各アプローチをいつ使用するかに関するアドバイス。
keySet()
の使用は、値をentrySet()
する必要がない限り、Map.get()
よりも高速です(便利であることに加えて)。