简体   繁体   中英

How to avoid of huge amount of key objects for different HashMaps

In my project in several places I use HashMap. Each of my HashMap should have a key with several fields like this:

 public Long campaignId;
    public Integer regionId;
    public String posaLang;
    public String audienceCode;
    public String theme;

    public GroupKey(Long campaignId,
                      Integer regionId,
                      String posaLang,
                      String audienceCode,
                      String theme) {

        this.campaignId = campaignId;
        this.regionId = regionId;
        this.posaLang = posaLang;
        this.audienceCode = audienceCode;
        this.theme = theme;
    }

    @Override
    public boolean equals(Object o) {
        if (this == o) return true;

        if (o == null || getClass() != o.getClass()) return false;

        AdGroupKey that = (AdGroupKey) o;

        return new EqualsBuilder()
                .append(regionId, that.regionId)
                .append(posaLang, that.posaLang)
                .append(audienceCode, that.audienceCode)
                .append(theme, that.theme)
                .isEquals();
    }

    @Override
    public int hashCode() {
        return new HashCodeBuilder(17, 37)
                .append(regionId)
                .append(posaLang)
                .append(audienceCode)
                .append(theme)
                .toHashCode();
    }
}

It's so huge amount of code, and for each HashMap I should write a key class as above. Is there a way to avoid of huge amout of this objects ?

I suspect your question would have attracted more views if it was titled "Best approach to composite keys in a HashMap".

There are many choices to choose from, and using a separate class for each key type may well be the best option. It is canonical and safe as it can represent any possible value made up of any combination of possible values from each of the fields. To minimize space overhead, think about whether you really need campaignId to be a Long object, or just a primitive long – in other words, can it be null?

You could combine all the fields into a single string, which could save space as you are then storing all the fields consecutively in memory instead of having separate reference variables. But this can be tricky. What will you use as a delimiter between fields? Are you sure this delimiter will never be part of a field?

You can store each field separately, as in the original option, but without having to write a class for each key type. All you need is a collection class that can store all the fields and provide suitable hashCode and equals methods that use the values of the fields. In fact, the List interface provides this. Its hashCode and equals method specifications are exactly what you need. They combine the hashCode and equals methods of each field in turn.

So, instead of a class, just use a List:

List<Object> myKey = Arrays.asList(campaignId, regionId, posaLang, audienceId);
HashMap<List<?>, ValueClass> myMap = new HashMap<>();
myMap.put(myKey, myValue);
myValue = myMap.get(Arrays.asList(campaignId, regionId, posaLang, audienceId));

Advantage: it's convenient, you don't have to write a class for each key.

Disadvantage: lack of type safety. You can't have homogeneous lists, so all fields have to be of type Object. There is no protection against creating a list with too many or too few objects, or objects of the wrong type.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM