web-dev-qa-db-ja.com

HashMapでのキー存在チェック

HashMapでキーの存在を確認することは常に必要ですか?

私は1000エントリを言うとHashMapを持っていると私は効率を向上させることを検討しています。 HashMapが非常に頻繁にアクセスされている場合は、アクセスごとにキーの存在を確認すると、大きなオーバーヘッドが発生します。キーが存在しないために例外が発生した場合は、例外をキャッチできます。 (これがめったに起こらないことを私が知っているとき)。これにより、HashMapへのアクセスが半分に減ります。

これは良いプログラミング方法ではないかもしれませんが、アクセス数を減らすのに役立ちます。それとも私はここで何かが足りないのですか?

[ Update ] HashMapにnull値がありません。

282
athena

Null値を格納したことはありますか?そうでなければ、あなただけのことができます:

Foo value = map.get(key);
if (value != null) {
    ...
} else {
    // No such key
}

そうでなければ、 を返すことができます あなたが返されたnull値を取得する場合は単に存在を確認します。

Foo value = map.get(key);
if (value != null) {
    ...
} else {
    // Key might be present...
    if (map.containsKey(key)) {
       // Okay, there's a key but the value is null
    } else {
       // Definitely no such key
    }
}
481
Jon Skeet

キーが存在することを確認しても何も得られません。これはHashMapのコードです。

@Override
public boolean containsKey(Object key) {
    Entry<K, V> m = getEntry(key);
    return m != null;
}

@Override
public V get(Object key) {
    Entry<K, V> m = getEntry(key);
    if (m != null) {
        return m.value;
    }
    return null;
}

get()の戻り値がnullと異なるかどうかを確認してください。

これがHashMapのソースコードです。


リソース:

63
Colin Hebert

もっと良い方法はHashMapのcontainsKeyメソッドを使うことです。明日のように、具体化するとマップにnullが追加されるので、そこにあるキーとnullの値を持つキーを区別する必要があります。

39
Dead Programmer

あなたはあなたのようなコードを持っているという意味ですか?

if(map.containsKey(key)) doSomethingWith(map.get(key))

あらゆる所に ?それならmap.get(key)がnullを返したかどうかをチェックしてください。ちなみに、HashMapは欠けているキーに対して例外を投げません。代わりにnullを返します。 containsKeyが必要とされる唯一のケースは、null値と欠損値を区別するためにnull値を格納するときですが、これは通常悪い習慣と考えられています。

21
jkff

わかりやすくするためにcontainsKey()を使用してください。それは速く、コードをきれいにそして読みやすく保ちます。 HashMapsのポイントは、キー検索が高速であることです。hashCode()equals()が正しく実装されていることを確認してください。

7
Mikko Wilkman
if(map.get(key) != null || (map.get(key) == null && map.containsKey(key)))
4
Erlan

Jon Skeetの答え は、2つのシナリオ(null値ではなくnull値でマップする)を効率的に解決します。

エントリー数と効率の問題について、何か追加したいと思います。

私は1.000エントリを言うとHashMapを持っていると私は効率を向上させることを検討しています。 HashMapが非常に頻繁にアクセスされている場合は、アクセスごとにキーの存在を確認すると、大きなオーバーヘッドが発生します。

1.000のエントリを持つマップは大きなマップではありません。
5.000または10.000のエントリを含む地図。
Mapは、そのような次元で素早く検索するように設計されています。

今、マップキーのhashCode()が良い分布を提供すると仮定します。

あなたがキータイプとしてIntegerを使うことができるならば、それをしてください。
衝突は一意のint値に対しては不可能であるため、そのhashCode()メソッドは非常に効率的です。

public final class Integer extends Number implements Comparable<Integer> {
    ...
    @Override
    public int hashCode() {
        return Integer.hashCode(value);
    }

    public static int hashCode(int value) {
        return value;
    }
    ...
}

キーのために、例えばStringでよく使われる別の組み込み型をMapとして使わなければならない場合、衝突があるかもしれませんが、Mapの中には1000から数千のオブジェクトがありますString.hashCode()メソッドは良いディストリビューションを提供します。

カスタムタイプを使用する場合は、hashCode()equals()を正しくオーバーライドして、全体としてhashCode()が公平に配布されるようにします。
Java Effectiveの項目9を参照している場合があります。
これが post です。

0
davidxxx

私は通常イディオムを使います

Object value = map.get(key);
if (value == null) {
    value = createValue(key);
    map.put(key, value);
}

これは、キーが見つからない場合にのみマップを2回押すということです。

0
Jon Freedman
  1. キークラスがあなたのものである場合は、hashCode()とequals()メソッドが実装されていることを確認してください。
  2. 基本的にHashMapへのアクセスはO(1)ですが、間違ったhashCodeメソッドの実装ではO(n)になります。同じハッシュキーを持つ値がリンクリストとして格納されるためです。
0
Boris

HashMapクラスで computeIfAbsent() メソッドを使用することもできます。

次の例では、mapはキー(銀行口座の名前)に適用されるトランザクションのリスト(整数)を格納します。 100200の2つのトランザクションをchecking_accountに追加するには、次のように書くことができます。

HashMap<String, ArrayList<Integer>> map = new HashMap<>();
map.computeIfAbsent("checking_account", key -> new ArrayList<>())
   .add(100)
   .add(200);

これにより、キーchecking_accountが存在するかどうかを確認する必要がなくなります。

  • 存在しない場合は、ラムダ式によって作成されて返されます。
  • 存在する場合は、キーの値がcomputeIfAbsent()によって返されます。

本当にエレガント! ????

0
nazmul idris