Is there a an implementation of the HashMap class (or Map interface) that will allow me to use alternate hashcode and equals operations... Similar to how collections of the same type can be sorted in multiple ways using the Comparator in Collections.sort(list, comparator).
I would like to avoid if possible, creating a key wrapper providing the desired hashcode and equals operations.
In my case, one of the scenarios why I need something like this:
In my web application, for each request, I load the Location/ISP and other data. In different parts of code (in my service and repository layers) I have "minimized" caches specific to its requirement.
Here is a simplified code example:
class GeoIpData{
private String countryName;
private String state;
private String city;
private String isp;
@Override
public int hashCode() {
//countryName hashCode
//state hashCode
//city hashCode
//isp hashCode
}
@Override
public boolean equals(Object obj) {
// compare countryName
// compare state
// compare city
// compare isp
}
}
Map<GeoIpData,#Type1> fullCache = ... //This cache needs to be unique per countryName,state,city and isp
Map<GeoIpData,#Type2> countryCache = ... //This cache needs to be unique per countryName
Map<GeoIpData,#Type2> ispCache = ... //This cache needs to be unique per countryName,isp
To achieve this the above 3 maps need 3 different hashcode and equals methods.
fullCache:
hashCode -> GeoIpData.hashCode();
equals -> GeoIpData.equals(Object obj);
countryCache:
hashCode -> {countryName hashCode }
equals -> {compare countryName }
ispCache:
hashCode -> {countryName hashCode & isp hashCode }
equals -> {compare countryName & compare isp hashCode }
In HashMap, hashCode() is used to calculate the bucket and therefore calculate the index. equals() method: This method is used to check whether 2 objects are equal or not. This method is provided by the Object class. You can override this in your class to provide your implementation.
You must override hashCode() in every class that overrides equals(). Failure to do so will result in a violation of the general contract for Object. hashCode(), which will prevent your class from functioning properly in conjunction with all hash-based collections, including HashMap, HashSet, and Hashtable.
We can conclude that to use a custom class for a key, it is necessary that hashCode() and equals() are implemented correctly. To put it simply, we have to ensure that the hashCode() method returns: the same value for the object as long as the state doesn't change (Internal Consistency)
If two keys are the same ( equals() returns true when you compare them), their hashCode() method must return the same number. If keys violate this, then keys that are equal might be stored in different buckets, and the hashmap would not be able to find key-value pairs (because it's going to look in the same bucket).
GNU Trove allows you to provide specific TObjectHashingStrategy with your own hash and equals functions for TCustomHashMap.
Initial Java API bounded equals
/ hashCode
behavior to type (class) because they didn't have lambdas back those days.
In order to reuse existing API / implementations - make ephemeral keys:
public CountryKey {
private String country;
@Override
public boolean equals(Object obj) {
if (!(obj instanceof CountryKey)) { return false; }
CountryKey that = (CountryKey) obj;
return this.country.equals(that.country);
}
@Override int hashCode() {
return country.hashCode();
}
}
or wrappers:
public CountryKey {
private GeoIpData holder;
@Override
public boolean equals(Object obj) {
if (!(obj instanceof CountryKey)) { return false; }
CountryKey that = (CountryKey) obj;
return this.holder.getCountry().equals(that.holder.getCountry());
}
@Override int hashCode() {
return holder.getCountry().hashCode();
}
}
and write helper constructors for keys:
public class GeoIpData {
public CountryKey buildCountryKey() {
return new CountryKey(this.country);
}
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With