回答:
[更新]
他の回答やコメントで述べたように、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は、レイジー計算された値を保存するため、インターフェイスに素敵な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/
Disclamer: この回答は、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;
}
}
Ed Staubのコメントで指定された理由とMapインターフェースの契約を破るので、実装でget(K key)メソッドをオーバーライドしないでください(これにより、見つけにくい場合があります)バグ)。
get
メソッドをオーバーライドしないことにポイントがあります。一方、ソリューションでは、インターフェイスを介してクラスを使用することはできません。これはよくあるケースです。
使用する:
myHashMap.getOrDefault(key, defaultValue);
これはデフォルトで行われます。戻りますnull
。
HashMap
ときに、この機能のためだけにサブクラス化するのは少しばかげているようですnull
。
NullObject
ただし、パターンを使用している場合や、コード全体にnullチェックを分散させたくない場合は問題があります。
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の新しいマップに初期化されています。
直接ではありませんが、クラスを拡張してgetメソッドを変更できます。以下は、すぐに使用できる例です。http://www.java2s.com/Code/Java/Collections-Data-Structure/ExtendedVersionofjavautilHashMapthatprovidesanextendedgetmethodaccpetingadefaultvalue.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も考慮してください。