HashMap возвращает значение по умолчанию для не найденных ключей?

Можно ли вернуть HashMap значение по умолчанию для всех ключей, которые не найдены в наборе?

Ответ 1

[Обновить]

Как отмечалось в других ответах и комментариях, Map#getOrDefault(...) с 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;
  }
}

Ответ 2

В Java 8 используйте Map.getOrDefault. Он берет ключ и возвращает значение, если соответствующий ключ не найден.

Ответ 3

Используйте DefaultsMap Commons, если вы не хотите изобретать велосипед, например,

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

Вы также можете передать существующую карту, если вы не отвечаете за ее создание.

Ответ 4

Java 8 представила хороший метод по умолчанию computeIfAbsent для интерфейса Map который хранит вычисленные с ленивым значением значения и поэтому не нарушает контракт карты:

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/

Отказ от ответственности: Этот ответ не совсем соответствует тому, что задавал OP, но может быть полезен в некоторых случаях, когда заголовок вопроса совпадает, когда число ключей ограничено и кэширование различных значений будет выгодным. Его не следует использовать в противоположном случае с большим количеством ключей и тем же значением по умолчанию, так как это приведет к ненужной трате памяти.

Ответ 5

Не можете ли вы создать статический метод, который делает именно это?

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

Ответ 6

Вы можете просто создать новый класс, который наследует 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;
    }
}

Я думаю, что вы не должны переопределять метод get (K key) в своей реализации из-за причин, указанных Ed Staub в его комментарии, и потому, что вы нарушите контракт интерфейса карты (это может потенциально привести к некоторым труднодоступным ошибкам).

Ответ 7

Использование:

myHashMap.getOrDefault(key, defaultValue);

Ответ 8

Он делает это по умолчанию. Он возвращает null.

Ответ 9

Я нашел LazyMap весьма полезным.

Когда метод get (Object) вызывается с ключом, который не существует на карте, фабрика используется для создания объекта. Созданный объект будет добавлен на карту с использованием запрошенного ключа.

Это позволяет вам сделать что-то вроде этого:

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

Вызов get создает значение по умолчанию для данного ключа. Вы указываете, как создать значение по умолчанию с аргументом factory для LazyMap.lazyMap(map, factory). В приведенном выше примере карта инициализируется новым AtomicInteger со значением 0.

Ответ 10

На Java 8+

Map.getOrDefault(Object key,V defaultValue)

Ответ 12

/**
 * 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));

Ответ 13

Мне нужно было прочитать результаты, возвращенные с сервера в JSON, где я не мог гарантировать, что поля будут присутствовать. Я использую класс org.json.simple.JSONObject, который является производным от HashMap. Вот некоторые вспомогательные функции, которые я использовал:

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; }
}   

Ответ 14

В смешанных проектах Java/Kotlin также рассмотрите Kotlin Map.withDefault.