Kümede bulunmayan HashMap
tüm anahtarlar için varsayılan değer döndürmek mümkün müdür ?
getOrDefault()
bağlantısı
Kümede bulunmayan HashMap
tüm anahtarlar için varsayılan değer döndürmek mümkün müdür ?
getOrDefault()
bağlantısı
Yanıtlar:
[Güncelleme]
Diğer cevaplar ve yorumcular tarafından belirtildiği gibi, Java 8'den itibaren arayabilirsiniz Map#getOrDefault(...)
.
[Orijinal]
Bunu tam olarak yapan bir Harita uygulaması yoktur, ancak HashMap'i genişleterek kendi uygulamanızı uygulamak önemsiz olacaktır:
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)
den (v == null && !this.containsKey(k))
' null
değerine ayarlamak isteyebilirsiniz . Biliyorum, bu sadece bir köşe davası, ancak yazar bunun içine girebilir.
!this.containsValue(null)
. Bu çok farklı !this.containsKey(k)
. containsValue
Bazı eğer çözüm başarısız olur diğer anahtarına açıkça değeri atanmıştır null
. Örneğin: map = new HashMap(); map.put(k1, null); V v = map.get(k2);
Bu durumda, v
yine de null
doğru olacak mı?
Java 8'de Map.getOrDefault kullanın . Anahtarı alır ve eşleşen anahtar bulunmazsa döndürülecek değeri alır.
getOrDefault
çok güzel, ancak haritaya her erişildiğinde varsayılan tanım gerektirir. Bir kez varsayılan bir değer tanımlamak, statik bir değerler haritası oluştururken okunabilirlik avantajlarına da sahip olacaktır.
private static String get(Map map, String s) { return map.getOrDefault(s, "Error"); }
Tekerleği yeniden icat etmek istemiyorsanız Commons ' DefaultedMap kullanın , örn.
Map<String, String> map = new DefaultedMap<>("[NO ENTRY FOUND]");
String surname = map.get("Surname");
// surname == "[NO ENTRY FOUND]"
Haritayı ilk etapta oluşturmaktan sorumlu değilseniz, mevcut bir haritayı da aktarabilirsiniz.
Java 8, tembel hesaplanmış değeri depolayan ve böylece harita sözleşmesini bozmayan arayüze hoş bir computeIfAbsent varsayılan yöntemi getirdiMap
:
Map<Key, Graph> map = new HashMap<>();
map.computeIfAbsent(aKey, key -> createExpensiveGraph(key));
Menşei: http://blog.javabien.net/2014/02/20/loadingcache-in-java-8-without-guava/
Feragatname: Bu cevap OP'nin istediği ile tam olarak eşleşmemektedir, ancak bazı durumlarda anahtar sayısı sınırlı olduğunda ve farklı değerlerin önbelleğe alınması karlı olduğunda soru başlığının eşleşmesi yararlı olabilir. Belleğin gereksiz yere boşa harcanacağı için bol miktarda anahtar ve aynı varsayılan değerle aksi durumda kullanılmamalıdır.
Tam olarak bunu yapan statik bir yöntem oluşturamaz mısınız?
private static <K, V> V getOrDefault(Map<K,V> map, K key, V defaultValue) {
return map.containsKey(key) ? map.get(key) : defaultValue;
}
HashMap'i devralan yeni bir sınıf oluşturabilir ve getDefault yöntemini ekleyebilirsiniz. İşte bir örnek kod:
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'un yorumunda belirttiği nedenlerden dolayı ve Harita arabiriminin sözleşmesini kıracağınızdan (bu potansiyel olarak bulunması zor olabilir) böcek).
get
Metodu geçersiz kılmamanın bir anlamı var . Öte yandan - çözümünüz sınıfın arabirim yoluyla kullanılmasına izin vermez, bu genellikle durumdur.
kullanın:
myHashMap.getOrDefault(key, defaultValue);
Bunu varsayılan olarak yapar. Geri döner null
.
HashMap
sadece bu işlevsellik için alt sınıfa geçmek bana biraz aptalca geliyor null
.
NullObject
desen kullanıyorsanız veya kodunuz boyunca boş denetimleri dağıtmak istemiyorsanız iyi değil - tamamen anladığım bir arzu.
LazyMap'i oldukça faydalı buldum .
Haritada bulunmayan bir anahtarla get (Object) yöntemi çağrıldığında, fabrika nesneyi oluşturmak için kullanılır. Oluşturulan nesne, istenen anahtar kullanılarak haritaya eklenir.
Bu, böyle bir şey yapmanıza izin verir:
Map<String, AtomicInteger> map = LazyMap.lazyMap(new HashMap<>(), ()->new AtomicInteger(0));
map.get(notExistingKey).incrementAndGet();
To çağrısı get
, verilen anahtar için varsayılan bir değer oluşturur. Varsayılan bağımsız değişkenin nasıl oluşturulacağını fabrika bağımsız değişkeniyle belirtirsiniz LazyMap.lazyMap(map, factory)
. Yukarıdaki örnekte, harita AtomicInteger
0 değerine sahip yeni bir değere başlatılır .
List<String>
- kabul edilen yanıtı kullanarak, bir fabrikadan (diyelim) ziyade her yeni anahtar için aynı listeyi kullanma riskini alırım new ArrayList<String>()
.
Doğrudan değil, ancak get yöntemini değiştirmek için sınıfı genişletebilirsiniz. İşte kullanım örneğine bir hazır: 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);
}
Örnek Kullanım:
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));
Alanların mevcut olacağını garanti edemedim JSON bir sunucudan döndürülen sonuçları okumak gerekiyordu. HashMap türetilmiş org.json.simple.JSONObject sınıfı kullanıyorum. İşte kullandığım bazı yardımcı fonksiyonlar:
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; }
}
Karışık Java / Kotlin projelerinde Kotlin'in Map.withDefault'u da düşünün .