web-dev-qa-db-ja.com

HashMapは、見つからないキーのデフォルト値を返しますか?

HashMapに、セットにないすべてのキーのデフォルト値を返すことは可能ですか?

128
Larry

[更新]

Java 8の時点で、他の回答とコメンターが指摘しているように、単に Map#getOrDefault(...) を呼び出すことができます。

[オリジナル]

これを正確に行うMap実装はありませんが、HashMapを拡張して独自に実装するのは簡単です。

public class DefaultHashMap<K,V> extends HashMap<K,V> {
  protected V defaultValue;
  public DefaultHashMap(V defaultValue) {
    this.defaultValue = defaultValue;
  }
  @Override
  public V get(Object k) {
    return containsKey(k) ? super.get(k) : defaultValue;
  }
}
114
maerics

Java 8では、 Map.getOrDefault を使用します。キーと、一致するキーが見つからない場合に返す値を受け取ります。

154
Spycho

ホイールを再発明したくない場合は、Commons ' DefaultedMap を使用します。

Map<String, String> map = new DefaultedMap<>("[NO ENTRY FOUND]");
String surname = map.get("Surname"); 
// surname == "[NO ENTRY FOUND]"

そもそもマップの作成を担当していない場合は、既存のマップを渡すこともできます。

70
Dave Newton

Java 8は、遅延計算された値を格納するMapインターフェイスにNice computeIfAbsent defaultメソッドを導入し、マップコントラクトを壊しません:

Map<Key, Graph> map = new HashMap<>();
map.computeIfAbsent(aKey, key -> createExpensiveGraph(key));

起源: http://blog.javabien.net/2014/02/20/loadingcache-in-Java-8-without-guava/

Disclamer:この回答は、OPが要求したものと完全には一致しませんが、キーの数が制限され、異なる値をキャッシュしている場合に質問のタイトルと一致する場合があると便利です有益だろう。これは、多くのキーと同じデフォルト値で反対の場合に使用しないでください。これは不必要にメモリを浪費するからです。

42
Vadzim

まさにこれを行う静的メソッドを作成することはできませんか?

private static <K, V> V getOrDefault(Map<K,V> map, K key, V defaultValue) {
    return map.containsKey(key) ? map.get(key) : defaultValue;
}
12
Shervin Asgari

HashMapを継承する新しいクラスを作成し、getDefaultメソッドを追加するだけです。サンプルコードを次に示します。

public class DefaultHashMap<K,V> extends HashMap<K,V> {
    public V getDefault(K key, V defaultValue) {
        if (containsKey(key)) {
            return get(key);
        }

        return defaultValue;
    }
}

Ed Staubのコメントで指定されている理由と、Mapインターフェイスの contract を壊すため、実装でget(Kキー)メソッドをオーバーライドしないでください見つけにくいバグに)。

10
Ivan Mushketyk

つかいます:

myHashMap.getOrDefault(key, defaultValue);
5
Diego Alejandro

デフォルトでこれを行います。 nullを返します。

3
mrkhrts

LazyMap が非常に役立つことがわかりました。

マップに存在しないキーを使用してget(Object)メソッドが呼び出されると、ファクトリを使用してオブジェクトが作成されます。作成されたオブジェクトは、要求されたキーを使用してマップに追加されます。

これにより、次のようなことができます。

    Map<String, AtomicInteger> map = LazyMap.lazyMap(new HashMap<>(), ()->new AtomicInteger(0));
    map.get(notExistingKey).incrementAndGet();

getを呼び出すと、指定されたキーのデフォルト値が作成されます。 LazyMap.lazyMap(map, factory)のファクトリ引数を使用して、デフォルト値の作成方法を指定します。上記の例では、マップは値が0の新しいAtomicIntegerに初期化されます。

2

Java 8+

Map.getOrDefault(Object key,V defaultValue)
1
Eduardo

フィールドが存在することを保証できなかったJSONのサーバーから返された結果を読み取る必要がありました。 HashMapから派生したorg.json.simple.JSONObjectクラスを使用しています。私が採用したいくつかのヘルパー関数は次のとおりです。

public static String getString( final JSONObject response, 
                                final String key ) 
{ return getString( response, key, "" ); }  
public static String getString( final JSONObject response, 
                                final String key, final String defVal ) 
{ return response.containsKey( key ) ? (String)response.get( key ) : defVal; }

public static long getLong( final JSONObject response, 
                            final String key ) 
{ return getLong( response, key, 0 ); } 
public static long getLong( final JSONObject response, 
                            final String key, final long defVal ) 
{ return response.containsKey( key ) ? (long)response.get( key ) : defVal; }

public static float getFloat( final JSONObject response, 
                              final String key ) 
{ return getFloat( response, key, 0.0f ); } 
public static float getFloat( final JSONObject response, 
                              final String key, final float defVal ) 
{ return response.containsKey( key ) ? (float)response.get( key ) : defVal; }

public static List<JSONObject> getList( final JSONObject response, 
                                        final String key ) 
{ return getList( response, key, new ArrayList<JSONObject>() ); }   
public static List<JSONObject> getList( final JSONObject response, 
                                        final String key, final List<JSONObject> defVal ) { 
    try { return response.containsKey( key ) ? (List<JSONObject>) response.get( key ) : defVal; }
    catch( ClassCastException e ) { return defVal; }
}   
0
BuvinJ

Java/Kotlin混合プロジェクトでは、Kotlinの Map.withDefault も考慮してください。

0
Vadzim

直接ではありませんが、クラスを拡張してgetメソッドを変更できます。すぐに使用できる例を次に示します: http://www.Java2s.com/Code/Java/Collections-Data-Structure/ExtendedVersionofjavautilHashMapthatprovidesanextendedgetmethodaccpetingadefaultvalue.htm

0
piokuc
/**
 * Extension of TreeMap to provide default value getter/creator.
 * 
 * NOTE: This class performs no null key or value checking.
 * 
 * @author N David Brown
 *
 * @param <K>   Key type
 * @param <V>   Value type
 */
public abstract class Hash<K, V> extends TreeMap<K, V> {

    private static final long serialVersionUID = 1905150272531272505L;

    /**
     * Same as {@link #get(Object)} but first stores result of
     * {@link #create(Object)} under given key if key doesn't exist.
     * 
     * @param k
     * @return
     */
    public V getOrCreate(final K k) {
        V v = get(k);
        if (v == null) {
            v = create(k);
            put(k, v);
        }
        return v;
    }

    /**
     * Same as {@link #get(Object)} but returns specified default value
     * if key doesn't exist. Note that default value isn't automatically
     * stored under the given key.
     * 
     * @param k
     * @param _default
     * @return
     */
    public V getDefault(final K k, final V _default) {
        V v = get(k);
        return v == null ? _default : v;
    }

    /**
     * Creates a default value for the specified key.
     * 
     * @param k
     * @return
     */
    abstract protected V create(final K k);
}

使用例:

protected class HashList extends Hash<String, ArrayList<String>> {
    private static final long serialVersionUID = 6658900478219817746L;

    @Override
        public ArrayList<Short> create(Short key) {
            return new ArrayList<Short>();
        }
}

final HashList haystack = new HashList();
final String needle = "hide and";
haystack.getOrCreate(needle).add("seek")
System.out.println(haystack.get(needle).get(0));
0
KomodoDave