HashMap返回未找到键的默认值?

时间:2011-09-22 18:02:51

标签: java dictionary hashmap

是否可以让HashMap为该组中找不到的所有键返回默认值?

15 个答案:

答案 0 :(得分:147)

在Java 8中,使用Map.getOrDefault。如果没有找到匹配的密钥,它将获取密钥和返回值。

答案 1 :(得分:104)

<强> [更新]

正如其他答案和评论者所述,从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 :(得分:70)

如果您不想重新发明轮子,请使用Commons'DefaultedMap,例如,

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

如果您不是首先负责创建地图,也可以传入现有地图。

答案 3 :(得分:40)

Java 8向Map接口引入了一个很好的computeIfAbsent默认方法,该方法存储了惰性计算值,因此不会破坏映射契约:

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所要求的不完全匹配,但在某些情况下,当密钥数量有限且不同值的缓存有利时,可能会在某些情况下匹配问题的标题。它不应该在相反的情况下使用大量的键和相同的默认值,因为这会不必要地浪费内存。

答案 4 :(得分:12)

难道你不能只创建一个完全符合这个要求的静态方法吗?

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

答案 5 :(得分:10)

您可以简单地创建一个继承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在他的评论中指定了原因,并且因为您将破坏Map接口的contract(这可能会导致一些难以发现的错误)。

答案 6 :(得分:5)

使用:

myHashMap.getOrDefault(key, defaultValue);

答案 7 :(得分:3)

默认情况下这样做。它返回null

答案 8 :(得分:2)

在Java 8+上

Map.getOrDefault(Object key,V defaultValue)

答案 9 :(得分:1)

我发现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

答案 10 :(得分:0)

不是直接的,但您可以扩展类以修改其get方法。这是一个随时可用的示例:http://www.java2s.com/Code/Java/Collections-Data-Structure/ExtendedVersionofjavautilHashMapthatprovidesanextendedgetmethodaccpetingadefaultvalue.htm

答案 11 :(得分:0)

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

答案 12 :(得分:0)

我需要在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; }
}   

答案 13 :(得分:0)

在Java / Kotlin混合项目中,还要考虑Kotlin的Map.withDefault

答案 14 :(得分:0)

    public final Map<String, List<String>> stringMap = new ConcurrentHashMap<String, List<String>>() {
        @Nullable
        @Override
        public List<String> get(@NonNull Object key) {
            return computeIfAbsent((String) key, s -> new ArrayList<String>());
        }
    };

HashMap导致死循环,因此请使用ConcurrentHashMap代替HashMap,