Is it possible to have a HashMap
return a default value for all keys that are not found in the set?

- 347,512
- 102
- 1,199
- 985

- 11,439
- 15
- 61
- 84
-
You can check for key existence and return default. Or extend the class and modify the behavior. or even you can use null - and put some check wherever you want to use it. – SudhirJ Sep 22 '11 at 18:10
-
2This is related / duplicate of http://stackoverflow.com/questions/4833336/map-implementation-that-allows-a-default-vaue-from-a-java-map-instead-of-null some other options are discussed there. – Mark Butler Dec 24 '12 at 08:58
-
4Check out the Java 8 solution for Map API `getOrDefault()` [link](https://docs.oracle.com/javase/8/docs/api/java/util/Map.html) – Trey Jonn Jun 27 '16 at 04:48
16 Answers
In Java 8, use Map.getOrDefault. It takes the key, and the value to return if no matching key is found.

- 7,698
- 3
- 34
- 55
-
22`getOrDefault` is very nice, but requires the default definition every time the map is accessed. Defining a default value once would also have readability benefits when creating a static map of values. – ach Aug 04 '14 at 14:19
-
4This is trivial to implement yourself. `private static String get(Map map, String s) { return map.getOrDefault(s, "Error"); }` – Jack Satriano Mar 10 '15 at 18:08
-
@JackSatriano Yeah but you'd have to hard-code the default value, or have a static variable for it. – H.v.M. Jan 14 '16 at 13:20
-
1See below the answer using computeIfAbsent, better when the default value is expensive or should be different each time. – hectorpal Jun 22 '17 at 05:43
-
1Though it is worse for memory, and will only save computation time if the default value is expensive to construct / compute. If it's cheap, you'll probably find it performs worse, as it has to insert into the map, rather than just returning a default value. Certainly another option though. – Spycho Jun 22 '17 at 12:23
-
-
@hectorpal If a value "should be different each time" you hardly can call it "default". – The incredible Jan Feb 17 '23 at 10:16
[Update]
As noted by other answers and commenters, as of Java 8 you can simply call Map#getOrDefault(...)
.
[Original]
There's no Map implementation that does this exactly but it would be trivial to implement your own by extending 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;
}
}

- 151,642
- 46
- 269
- 291
-
23Just to be precise, you may want to adjust the condition from `(v == null)` to `(v == null && !this.containsKey(k))` in case they purposely added a `null` value. I know, this is just a corner case, but the author may run into it. – Adam Paynter Sep 22 '11 at 18:17
-
@maerics: I noticed that you used `!this.containsValue(null)`. This is subtly different from `!this.containsKey(k)`. The `containsValue` solution will fail if some *other* key has been explicitly assigned a value of `null`. For example: `map = new HashMap(); map.put(k1, null); V v = map.get(k2);` In this case, `v` will still be `null`, correct? – Adam Paynter Sep 22 '11 at 18:42
-
21_In general_, I think this is a bad idea - I'd push the defaulting behavior into the client, or a delegate that doesn't claim to be a Map. In particular, the lack of valid keySet() or entrySet() will cause problems with anything that expects the Map contract to be respected. And the infinite set of valid keys that containsKey() implies is likely to cause bad performance that's hard to diagnose. Not to say, though, that it might not serve some particular purpose. – Ed Staub Sep 22 '11 at 18:48
-
One problem with this approach is if the value is a complicated object. Map
#put won't work as expected. – Eyal Nov 05 '14 at 14:53 -
Does not work on ConcurrentHashMap. There, you should check get's result for null. – dveim Nov 06 '15 at 17:15
-
@Eyal Depends on what you expect, I guess, but to make your point explicit, it would use the same list for each new key instead of creating a new list. – Dave Newton Mar 11 '16 at 14:55
-
-
Did anyone face this issue https://stackoverflow.com/questions/13032977/hashmap-getobject-always-returns-string-instead-of-other-object after using this answer? – Joker Apr 27 '21 at 15:37
Use Commons' DefaultedMap if you don't feel like reinventing the wheel, e.g.,
Map<String, String> map = new DefaultedMap<>("[NO ENTRY FOUND]");
String surname = map.get("Surname");
// surname == "[NO ENTRY FOUND]"
You can also pass in an existing map if you're not in charge of creating the map in the first place.

- 5,839
- 1
- 51
- 72

- 158,873
- 26
- 254
- 302
-
30+1 although sometimes its easier to reinvent the wheel than to introduce large dependencies for tiny slices of simple functionality. – maerics Sep 22 '11 at 19:39
-
5and funny thing is, that many projects that I work with already have something like this in classpath (either Apache Commons or Google Guava) – bartosz.r Feb 20 '13 at 15:53
-
1
Java 8 introduced a nice computeIfAbsent default method to Map
interface which stores lazy-computed value and so doesn't break map contract:
Map<Key, Graph> map = new HashMap<>();
map.computeIfAbsent(aKey, key -> createExpensiveGraph(key));
Origin: http://blog.javabien.net/2014/02/20/loadingcache-in-java-8-without-guava/
Disclamer: This answer doesn't match exactly what OP asked but may be handy in some cases matching question's title when keys number is limited and caching of different values would be profitable. It shouldn't be used in opposite case with plenty of keys and same default value as this would needlessly waste memory.

- 24,954
- 11
- 143
- 151
-
1Not what OP asked: he wants no side effect on the map. Also, storing the default value for each absent key is a useless loss of memory space. – numéro6 Jul 12 '17 at 13:19
-
@numéro6, yes, this doesn't match exactly what OP asked but some googling people still find this side answer useful. As other answers mentioned, it's impossible to achieve exactly what OP asked without breaking map contract. Another workaround not mentioned here is to [use another abstraction instead of Map](https://stackoverflow.com/a/20982458/603516). – Vadzim Jul 12 '17 at 13:56
-
It's possible to achieve exactly what OP asked without breaking map contract. No workaround is needed, just using getOrDefault is the right (most updated) way, computeIfAbsent is the wrong way: you will lose time calling the mappingFunction and memory by storing the result (both for each missing keys). I can't see any good reason to do that instead of getOrDefault. What I'm describing is the exact reason why there are two distinct methods on the Map contract: there are two distinct use-cases that should not be confused (I had to fix some at work). This answer spread the confusion. – numéro6 Jul 13 '17 at 15:01
Can't you just create a static method that does exactly this?
private static <K, V> V getOrDefault(Map<K,V> map, K key, V defaultValue) {
return map.containsKey(key) ? map.get(key) : defaultValue;
}

- 23,901
- 30
- 103
- 143
You can simply create a new class that inherits HashMap and add getDefault method. Here is a sample code:
public class DefaultHashMap<K,V> extends HashMap<K,V> {
public V getDefault(K key, V defaultValue) {
if (containsKey(key)) {
return get(key);
}
return defaultValue;
}
}
I think that you should not override get(K key) method in your implementation, because of the reasons specified by Ed Staub in his comment and because you will break the contract of Map interface (this can potentially lead to some hard-to-find bugs).

- 8,107
- 7
- 50
- 67
-
4You've got a point in not overriding the `get` method. On the other hand - your solution doesn't allow using the class via interface, which might often be the case. – Krzysztof Jabłoński Jan 21 '14 at 07:59
-
@Krzysztof Jabłoński Why shouldn't this class work via interface? – The incredible Jan Feb 17 '23 at 10:22
-
@TheincredibleJan `getDefault` method wouldn't be available though the `Map` interface, so it would only work like a regular `HashMap`. – Krzysztof Jabłoński Feb 22 '23 at 13:09
It does this by default. It returns null
.

- 829
- 7
- 17
-
@Larry, Seems a little silly to me to subclass `HashMap` just for this functionality when `null` is perfectly fine. – mrkhrts Sep 22 '11 at 18:11
-
17It's not fine if you're using a `NullObject` pattern, though, or don't want to scatter null-checks throughout your code--a desire I completely understand. – Dave Newton Aug 24 '12 at 13:34
-
I found the LazyMap quite helpful.
When the get(Object) method is called with a key that does not exist in the map, the factory is used to create the object. The created object will be added to the map using the requested key.
This allows you to do something like this:
Map<String, AtomicInteger> map = LazyMap.lazyMap(new HashMap<>(), ()->new AtomicInteger(0));
map.get(notExistingKey).incrementAndGet();
The call to get
creates a default value for the given key. You specify how to create the default value with the factory argument to LazyMap.lazyMap(map, factory)
. In the example above, the map is initialized to a new AtomicInteger
with value 0.

- 4,853
- 4
- 32
- 42
-
This has an advantage over the accepted answer in that the default value is created by a factory. What if my default value is `List
` -- using the accepted answer I'd risk using the *same* list for each new key, rather than (say) a `new ArrayList – Jan 04 '19 at 08:28()` from a factory.
/**
* 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);
}
Example Usage:
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));

- 7,239
- 10
- 60
- 92
I needed to read the results returned from a server in JSON where I couldn't guarantee the fields would be present. I'm using class org.json.simple.JSONObject which is derived from HashMap. Here are some helper functions I employed:
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; }
}

- 10,221
- 5
- 83
- 96
-
Couldn't your object simply have had members with default values by itself? Then it wouldn't matter if there was something in the JSON. – The incredible Jan Feb 17 '23 at 10:31
-
This post was from 7 years ago. I don't remember writing this now. But, what you are saying conceptually makes no sense. I guess you are suggesting creating an object, filling the whole thing in with default values, and then writing an if containsKey statement around every potential assignment from the JSON, plus the type casts? Instead of rolling all that functionality into some reusable functions? – BuvinJ Feb 17 '23 at 13:42
-
That would be a) slower, b) involve dramatically more lines c) have to be repeated over and over whenever this need arose c) be ugly... I could point to a whole lot of standard libraries/classes which use this coding pattern. – BuvinJ Feb 17 '23 at 13:43
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 cause dead loop, so use ConcurrentHashMap instead of HashMap,

- 1,172
- 1
- 8
- 13
In Map Using getOrDefault method if key is not found we can place the default value in right side parameter.
Converting List to Map by doing grouping Status.
Map<String, Long> mapClaimDecisionSummaryCount = reportList.stream().collect(Collectors.groupingBy(Report::getStatus, Collectors.counting()));
Long status_approved = mapClaimDecisionSummaryCount.getOrDefault("APPROVED", 0L);
Long status_declined = mapClaimDecisionSummaryCount.getOrDefault("DECLINED", 0L);
Long status_cancelled = mapClaimDecisionSummaryCount.getOrDefault("CANCELLED", 0L);//If Key not found it takes defaultValue as 0
Long status_inprogress = mapClaimDecisionSummaryCount.getOrDefault("INPROGRESS", 0L);
System.out.println("APPROVED: "+ status_approved);
System.out.println("DECLINED: "+ status_declined);
System.out.println("CANCELLED: "+ status_cancelled);
System.out.println("INPROGRESS: "+ status_inprogress);
OutPut:
APPROVED: 20
DECLINED: 10
CANCELLED: 5
INPROGRESS: 0
As you see in the above output Status INPROGRESS is not found, so it takes Default value as 0

- 6,579
- 7
- 67
- 92
-
I don't see that INPROGRESS is not found as long as reportList magically appears out of nowhere. – The incredible Jan Feb 17 '23 at 10:28
Not directly, but you can extend the class to modify its get method. Here is a ready to use example: http://www.java2s.com/Code/Java/Collections-Data-Structure/ExtendedVersionofjavautilHashMapthatprovidesanextendedgetmethodaccpetingadefaultvalue.htm

- 25,594
- 11
- 72
- 102