Understanding HashMap<K,V> - java

Ok, here is the bit I do not understand.
If you attempt to retrieve an object using the get() method and null is returned, it is still possible that null may be stored as the object associated with the key you supplied to the get() method. You can determine if this is the case by passing your key of the object to containsKey() method for map. This returns true if key is stored in the map
So, how is containsKey() supposed to tell me if the value associated with the key supplied is null?
This is the reference if you wanna check. Page 553

Map<String, Object> map = new HashMap<String, Object>();
map.put("Foo", null);
System.out.println(map.containsKey("Foo"));
System.out.println(map.containsKey("Boo"));
OUTPUT:
true
false
get() returns null in two cases:
The key does not exist in the map.
The key does exist but the associated value is null.
You can't tell from get() which is true. However, containsKey() will tell you if the key was present in the map, regardless of whether its associated value was null.

Consider this simple snippet of code:
Map<String, String> m = new HashMap<String, String>();
m.put("key1", "value1");
m.put("key2", null);
System.out.println("m.get(\"key1\")=" + m.get("key1"));
System.out.println("m.containsKey(\"key1\")=" + m.containsKey("key1"));
System.out.println("m.get(\"key2\")=" + m.get("key2"));
System.out.println("m.containsKey(\"key2\")=" + m.containsKey("key2"));
System.out.println("m.get(\"key3\")=" + m.get("key3"));
System.out.println("m.containsKey(\"key3\")=" + m.containsKey("key3"));
As you can see I put in the map two values, one of which is null. Thene i asked the map for three values: two of them are present (one is null), one is not. Look at the result:
m.get("key1")=value1
m.containsKey("key1")=true
m.get("key2")=null
m.containsKey("key2")=true
m.get("key3")=null
m.containsKey("key3")=false
The second and the third are the tricky part. key2 is present with null value so, using get() you cannot discriminate whether the element is not in the map or is in the map with a null value. But, using containsKey() you can, as it returns a boolean.

(get() == null && containsKey()) == value is null

containsKey would tell you if the key is in the hashmap at all. Consider the case where a key is present with null value and the other case in which the key which you are looking for is not at all in the hashmap.

Related

Hashmap : How map works when we put same key [duplicate]

This question already has answers here:
What happens when a duplicate key is put into a HashMap?
(12 answers)
Closed 3 years ago.
Map<String, String> map = new HashMap<String, String>();
I am aware about the internal working of map. if the hashcode for two keys are same collision occurs and it will store in linkedlist. but what if put that key again.
is there any check on that ? or it will simply replace the value without checking ?
to elaborate more
map.put("sparsh", "sparsh");
map.put("sparsh", "1");
it will replace value "sparsh" to "1"
map.put("sparsh", "1");
map.put("sparsh", "1");
what will happen in above case, any replacement ?
and some different context from above question
System.out.println(map.put("sparsh", "sparsh"));
System.out.println(map.put("sparsh", "1"));
it is giving me first "null" and then "sparsh"(key). what is the reason behind that, if anyone has clarity about that.
The contract of put is:
when the key is unknown, you add a new key/value pair,
when the key is known, you update (overwrite) the value of an existing key/value pair.
In your case, you can't observe the difference between "putting in" the new value, or keeping the old one. Two strings with two values are always equal, thus it doesn't really matter anyway.
But then: you can easily construct an example (using a class with two fields) where two objects are equal, but yet have different values (because only one of the two fields is used within the equals() implementation) .
And therefore the new value must go into the map, even if it is equal to the one already present.
From documentation of Map::put :
V put(K key, V value)
Returns: the previous value associated with key, or null if there was
no mapping for key. (A null return can also indicate that the map
previously associated null with key, if the implementation supports
null values.)
What does this mean
When you add an entry to the map :
if the entry with that key exist then it will return the last value,
else it will return null as you get in your example.
Here is an example with multiple puts :
System.out.println(map.put("key", "v1")); // null
System.out.println(map.put("key", "v2")); // v1
System.out.println(map.put("key", "v3")); // v2
System.out.println(map.put("key2", "v4")); // null
java.util.Map.put(key, value) returns the previous value associated with the same key.
So initially, there is no value associated with the key, so the first map.put("sparsh", "sparsh") returns null.
Then, since you have key: sparsh, value: sparsh in the map, calling map.put("sparsh", "1") will return the previous value, as in "sparsh"

Can I declare a HashMap<key> instead of a HashMap<key,value>?

I'm trying to insert keys into a hashmap but I don't really need values inserted. I could but they wouldn't be used. I know hashmaps can accept null keys and values but only one null key,value pair. I could map.put(key,null) with the values being null but that method seems inefficient. My intention is that I'm going to use the map.containsKey(key) method to determine if a key exists in a hashmap which is why I don't need a value.
With that being said, is there a way to declare HashMap<key> instead of HashMap<key,arbitraryValue> so I won't have to add unnecessary null values? Sorry if this may be a dumb question.
As Jacob G. said, you should use a Set<E>.
A set is just a collection that does not contain any duplicates. The implementing class HashSet<E> actually uses a HashMap<K,V> under the hood, as mentioned by Ole V.V., but using a Set<E> in your code is the better approach IMO, because your problem does not require the values.
Additionally, there is a problem with using a HashMap<K,V> where all your values are null is in the get(K key) method. This method will return null if the requested key does not have an associated value. So how do you know if your call to get returned a valid or invalid null? i.e.
Map<Integer, Object> map = new HashMap<>();
// add entry 0 ->
map.put(0, null);
Object get1 = map.get(0); // returns null, so 0 must be a key in our map!
Object get2 = map.get(1); // also returns null, so is 1 a key too? No!
So, for your specific problem, I would try something like this!
Set<MyKey> set = new HashSet<>(); // or any implementing class
...
MyKey someKey = ...
// Check if your key set doesn't have some key, if so add it to the key set
if (!set.contains(someKey)) {
set.add(someKey);
}

Does ConcurrentHashmap size() method count null keys?

Lets say I have a concurrenthashmap with some keys and values that are not null. Later these keys can become null, then what happens? Are they automatically removed from concurrenthashmap or do they stay there as null? Does the size() method count them?
Most Java Maps can contain null values.
The following code is perfectly valid and will return a size of 1.
Map m = new HashMap<String, String>();
m.put("foo", null);
System.out.println(m.size()); //will print "1"
This is because HashMap allows for null values.
Turns out, however, based on my testing, that the following code will NOT work.
Map m = new ConcurrentHashMap<String, String>();
m.put("foo", null); //Will throw a NullPointerException
This is because, apparently, ConcurrentHashMap does not allow for null values.
According to the Javadoc(http://docs.oracle.com/javase/7/docs/api/java/util/Map.html):
Some map implementations have restrictions on the keys and values they may contain. For example, some implementations prohibit null keys and values, and some have restrictions on the types of their keys.
So, there you have it. Hope this helps :)
From ConcurrentHashMap API:
Like Hashtable but unlike HashMap, this class does not allow null to be used as a key or value.

How to access HashMap in JSP by Object key (rather than String)

I can access a HashMap<String, Object> easily enough in JSTL but is it possible to access a HashMap<Object, Object>
I only ask because I don't receive any errors (or output) when trying the following:
${myHashMap[anObject]}
It leads me to believe that myHashMap is trying to find my value but it is somehow not evaluating anObject as the correct key. I can verify that myHashMap has anObject as a key with a (non-blank/non-null) value that should display.
This syntax ought indeed to work. I understand that you didn't get any value by the given object as key although you're confident that the desired object is in there? In that case, the class as represented behind ${anObject} in your code must have the equals() (and hashCode()) methods properly implemented. The Map#get() namely tests the key by equals() method. See also the javadoc:
Returns the value to which the specified key is mapped, or null if this map contains no mapping for the key.
More formally, if this map contains a mapping from a key k to a value v such that (key==null ? k==null : key.equals(k)), then this method returns v; otherwise it returns null. (There can be at most one such mapping.)
In other words, if the equals() of your ${anObject} returns true for the map key, then the associated map value will be returned, otherwise null will be returned and EL will then print nothing.
That it works for String is simply because that class has the equals() already properly implemented.
See also:
Right way to implement equals contract

Return from HashMap<String, String> when no key

What does a HashMap<String,String> return when I call map.get("key") and I don't have an entry with the key "key" in the HashMap?
It returns null. It's written in the documentation.
Returns:
the value to which the specified key is mapped, or null if this map contains no mapping for the key
The first thing to do when you have such a specific question is to consult the documentation. Java APIs are documented reasonably well and tell you what is returned, what exceptions are thrown and what each argument means.
You can:
Check in your IDE
Map<String, String> map = new HashMap<String, String>();
map.put("foo", "fooValue");
System.out.println(map.get("bar")); // null
Check documentation - HashMap get() method description:
Returns the value to which the
specified key is mapped, or null if
this map contains no mapping for the
key.
Careful -
If you initialize it using
Map.of(key, val, key, val)
and then do a
get('key-that-isnt-there')
then you'll get a null pointer exception.

Categories

Resources