Reputation: 3596
I'm trying to create a version of the HashMap that doesn't replace the value if a duplicate key is entered, but actually adds the two corresponding values together. The key value must be of type Number
so that adding can occur. However, it doesn't seem to understand that my V
is of type Number
, or at least it does until I try to call super.put
. It's as if the V
in HashMap
is not actually the same V
as the one that I declared to extend Number
.
What is going on here?
public class AdditiveMap<K, V extends Number> extends HashMap<K, V>
{
@Override
public V put(final K key, final V value)
{
if (containsKey(key))
// Second param Found 'Number', required 'V'
super.put(key, (Number)(get(key).intValue() + value.intValue()));
else
super.put(key, value);
}
}
Upvotes: 0
Views: 76
Reputation: 140309
Don't create a Map
which does this in the put
method. The contract of the Map.put
method is (emphasis mine):
Associates the specified value with the specified key in this map (optional operation). If the map previously contained a mapping for the key, the old value is replaced by the specified value. (A map m is said to contain a mapping for a key k if and only if m.containsKey(k) would return true.)
As such, your map would violate the contract of the interface.
You are, of course, free to add a AdditiveMap.addValuesTogether
(or whatever) method. But you'd be best off just using the existing merge
method:
map.merge(key, newValue, v -> v + newValue);
The main advantage of this is that this same syntax works for all numeric types (well, for int
, long
, float
and double
; you'd need a cast for short
, char
and byte
because they are widened to int
when you add them; you could avoid the explicit cast by using v -> v += newValue
); but you actually can't do what you're trying to do generically (without providing a Merger<V>
strategy, which can add a V
to another V
; and that's just very heavyweight compared to using this existing method).
Upvotes: 6