是否可以为HashMap
集合中未找到的所有键返回默认值?
是否可以为HashMap
集合中未找到的所有键返回默认值?
Answers:
[更新]
正如其他答案和评论者所指出的那样,从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;
}
}
(v == null)
到(v == null && !this.containsKey(k))
,以防他们有意添加了一个null
值。我知道,这只是一个小案例,但作者可能会遇到。
!this.containsValue(null)
。这与稍有不同!this.containsKey(k)
。该containsValue
如果一些解决失败等重点已经明确分配的值null
。例如:map = new HashMap(); map.put(k1, null); V v = map.get(k2);
在这种情况下,v
仍然null
正确吗?
在Java 8中,使用Map.getOrDefault。它需要密钥,如果找不到匹配的密钥,则返回值。
getOrDefault
非常好,但是每次访问地图时都需要使用默认定义。创建静态值映射时,一次定义默认值也将具有可读性。
private static String get(Map map, String s) { return map.getOrDefault(s, "Error"); }
如果您不想重新发明轮子,请使用Commons的DefaultedMap,例如,
Map<String, String> map = new DefaultedMap<>("[NO ENTRY FOUND]");
String surname = map.get("Surname");
// surname == "[NO ENTRY FOUND]"
如果您首先不负责创建地图,则也可以传递现有地图。
Java 8 在接口中引入了一个不错的validateIfAbsent默认方法,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要求的内容不完全匹配,但在某些情况下,如果键数受到限制并且缓存不同的值将有利可图,则可以很方便地匹配问题的标题。不应在带有大量键和相同默认值的相反情况下使用它,因为这会不必要地浪费内存。
您不能只创建一个完全做到这一点的静态方法吗?
private static <K, V> V getOrDefault(Map<K,V> map, K key, V defaultValue) {
return map.containsKey(key) ? map.get(key) : defaultValue;
}
您可以简单地创建一个继承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接口的合同(这可能会导致一些难以发现的问题)错误)。
get
方法。另一方面,您的解决方案不允许通过接口使用类,这种情况经常会发生。
默认情况下会这样做。它返回null
。
HashMap
对于这种功能,当我null
完全满意的时候,我似乎有些愚蠢。
NullObject
模式,或者不想在整个代码中分散空检查,那是不对的,我完全理解这一愿望。
我发现LazyMap很有帮助。
当使用映射中不存在的键调用get(Object)方法时,将使用工厂创建对象。使用请求的键将创建的对象添加到地图。
这使您可以执行以下操作:
Map<String, AtomicInteger> map = LazyMap.lazyMap(new HashMap<>(), ()->new AtomicInteger(0));
map.get(notExistingKey).incrementAndGet();
调用get
会为给定的键创建一个默认值。您可以使用的工厂参数指定如何创建默认值LazyMap.lazyMap(map, factory)
。在上面的示例中,映射被初始化为AtomicInteger
值为0 的新映射。
不是直接的,但是您可以扩展类以修改其get方法。这是一个现成的示例:http : //www.java2s.com/Code/Java/Collections-Data-Structure/ExtendedVersionofjavautilHashMap,它提供了扩展的getmethodaccpetingadefaultvalue.htm
/**
* 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));
我需要读取从服务器以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; }
}
在Java / Kotlin混合项目中,还要考虑Kotlin的Map.withDefault。