What Happens When a Duplicate Key Is Put into a Hashmap

How do I handle duplicate keys in HashMaps in Java?

To achieve what you actually ask for:

Before your put line:

while (data.containsKey(key)) key += "_";
data.put(key, value);

This will keep on checking the map to see if key already exists, and if it does, it adds the _ to the end, and tries again.

You can do these two lines in one:

while (data.putIfAbsent(key, value) != null) key += "_";

This does basically the same, but it just avoids having to look up twice in the case that the key isn't found (and thus the value should be inserted).


However, consider whether this is actually the best thing to do: how will you then look up things by "key", if you've essentially made up the keys while reading them.

You can keep multiple values per key by using a value type which stores multiple values, e.g. List<String>.

HashMap<String, List<String>> data = new HashMap<>(); 
// ...
data.computeIfAbsent(key, k -> new ArrayList<>()).add(value);

Why Hashmap values are getting replaced when duplicate key are used, even though it uses linked list for each bucket internally?

You inserted the values 1, 2, 3 into key 1, and the values 1, 2 into key 2. Each time you insert a value into a key, you overwrite the value which previously existed at the key, assuming there were a previous value. So, your code is functionally identical to this:

HashMap<Integer, Integer> map = new HashMap<Integer, Integer>();
map.put(1, 3);
map.put(2, 2);

That is, only the latest key-value assignments actually "stick."

Map implementation with duplicate keys

You are searching for a multimap, and indeed both commons-collections and Guava have several implementations for that. Multimaps allow for multiple keys by maintaining a collection of values per key, i.e. you can put a single object into the map, but you retrieve a collection.

If you can use Java 5, I would prefer Guava's Multimap as it is generics-aware.

HashMap holding duplicate keys

HashMap is not thread safe, as explicitly noted in the linked docs. You are providing a good example of why this is so. Yes, you are putting in duplicate keys because put does not check that another thread is putting the same key in. That is what it means not to be thread safe.

The retrieval behavior is undefined, so it can return whichever value it wants at that point. It is probably very implementation, platform and even timing-dependent.

There are a couple of workarounds. The one suggested in the docs is

Map m = Collections.synchronizedMap(new HashMap(...));

Another option is to use ConcurrentHashMap, which is explicitly designed for the purpose.

HashMap creating duplicate keys?

HashMap uses hashing function to calculate indices for objects used as key. For this functionality to work properly you need to provide both equals() AND hashCode() functions for class that instances of you plan to use as keys in your hash map.

That means you need to override public int hashCode() method that's now inherited straight from Object superclass, and put there some calculations that will return the same integer for objects that are considered 'equal'. Fortunately you compare Strings as this criteria so you can use String method hashCode resulting with:

@Override
public int hashCode() {
return s.hashCode();
}

Second problem that I previously missed is your implementation of equals() is wrong. You should override Object's equals() which has a signature public boolean equals( Object o ) and you implemented it with Vertex as an argument, which caused that while adding to hashmap Object's equals was used, as you didn't override by overload equals. That's one of the reasons that annotation @Overrideshould be used, compiler would tell you that you don't override anything and you would know that you're doing something wrong. Now, going back to how to implementequals` properly....

@Override
public boolean equals(Object o) {
if( o instanceof Vertex ) {
return s.equals((( Vertex)o).getName());
} else {
return false;
}
}

Now instances of Vertex will behave properly when used as key in hash map.

As a side note, putting all the logic, including opening, parsing file in constructor is a little too much to my taste, consider splitting it into some methods instead.

Java HashMap when duplicate keys are inserted

Your output is printing the keys, not the values. In your code the key will not change but the value will.

For instance, if you change your output loop to:

for (Emp emp : emp.values()) {
System.out.println("Name: " + e.name + " , age: " + e.age);
}

I suspect you'll see the answer you were expecting.

However: In general I would advise against doing what you're doing here. All kinds of code expects that if a.equals(b) then a and b don't have any meaningful differences at all, and your Emp class's equals implementation doesn't live up to that contract. For instance, if you used a HashSet rather than a HashMap you would get much more peculiar behavior and there'd be no way to fix it.

A better way to implement this might be to have Emp's hashCode and equals methods properly respect name and age, and make your map be a Map<String, Emp> where the key is the employee's name and the value is the Emp record.



Related Topics



Leave a reply



Submit