1

I have following scenario (modified one than actual business purpose).

  1. I have a program which predicts how much calories a person will loose for the next 13 weeks based on certain attributes.
  2. I want to cache this result in the database so that i don't call the prediction again for the same combination.
  3. I have class person class Person { int personId; String weekStartDate; }
  4. I have HashMap<List<Person>, Integer> - The key is 13 weeks data of a person and the value is the prediction
  5. I will keep the hashvalue in the database for caching purpose

Is there a better way to handle above scenario? Any design pattern to support such scenarios

Federico klez Culloca
  • 22,898
  • 15
  • 55
  • 90
i0707
  • 567
  • 1
  • 4
  • 14
  • I have HashMap, Integer> - The key is 13 weeks data of a person and the value is the prediction ---> The person objects are not really data right? Since they only contain personIds and dates? – Stefan Apr 06 '18 at 13:08
  • 1
    Also, it seems a bit counter-intuitive to me that a list of persons is the 13-week data for a single person. That's a good candidate for a class on its own. – Federico klez Culloca Apr 06 '18 at 13:10
  • Your data structure is incorrect. The key appears to be a collection of different people. In general, any mutable object should not be used as a key in a `HashMap` as any change to any contained value will break the map and prevent finding the object later. – Jim Garrison Apr 06 '18 at 13:10
  • As far as having `HashMap< List < Person>, Integer>`, Yes you can do that. – Mayur Apr 06 '18 at 13:12
  • @FedericoklezCulloca, 13 weeks is a dynamic one, it depends on input parameter. In another case it can predict for next 6 weeks – i0707 Apr 06 '18 at 13:12
  • @i0707 that's not my point. My point is that when I see a class named `Person` I don't really think it means week. – Federico klez Culloca Apr 06 '18 at 13:14
  • @FedericoklezCulloca, may be i should have modified the class like this Class Person {int personId, String weekStartDate, int hoursExcercised} – i0707 Apr 06 '18 at 13:19
  • related: https://stackoverflow.com/questions/7842049/are-mutable-hashmap-keys-a-dangerous-practice – jaco0646 Apr 06 '18 at 18:20
  • I noticed that your question is still "open" - as you didn't accept an answer. Please have a look and decide if you want to [accept](https://meta.stackexchange.com/questions/5234/how-does-accepting-an-answer-work) an answer. Or let me know if there is something I can do to enhance my input to make it accept worthy. Accepting helps future readers to determine if the problem is solved, and shows appreciation for the people who took the time answering you. Thanks! – GhostCat Aug 10 '18 at 13:39

3 Answers3

5

Depends: the implementation of hashCode() uses the elements of your list. So adding elements later on changes the result of that operation:

public int hashCode() {
    int hashCode = 1;
    for (E e : this)
        hashCode = 31*hashCode + (e==null ? 0 : e.hashCode());
    return hashCode;
}

Maps aren't build for keys that can change their hash values! And of course, it doesn't really make sense to implement that method differently.

So: it can work when your lists are all immutable, meaning that neither the list nor any of its members is modified after the list was used as key. But there is a certain risk: if you forget about that contract later on, and these lists see modifications, then you will run into interesting issues.

GhostCat
  • 127,190
  • 21
  • 146
  • 218
  • the elements are fixed, that person object is meant only for key formation, we will override the hashcode and equals. Will still be a bad design? – i0707 Apr 06 '18 at 13:14
  • 1
    @i0707 It should work, but the idea isn't very robust. If you ever *violate* this implicit contract (which is hard to enforce) you will run into all kind of weird errors. – GhostCat Apr 06 '18 at 13:15
1

This works because the hashcode of the standard List implementations is computed with the hashcodes of the contents. You need to make sure, however, to also implement hashCode and equals in the Person class, otherwise you will get the same problem this guy had. See also my answer on that question.

kutschkem
  • 6,194
  • 3
  • 16
  • 43
1

I would suggest you define a class (say Data) and use it as a key in your hashmap. Override equals/hashcode accordingly with knowledge of data over weeks.

Nrj
  • 6,226
  • 6
  • 44
  • 56