0
class UserScoring implements Comparable<UserScoring> {

        User user;
        int score;

        UserScoring(User user, int score) {
            this.user = user;
            this.score = score;
        }

        @Override
        public int compareTo(UserScoring o) {
            if (this.score < o.score) {
                return 1;
            }
            else if (this.score == o.score) {
                return 0;
            }
            return -1;
        }

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

        public boolean equals(Object obj) {
            if (obj == null) {
                return false;
            }
            if (getClass() != obj.getClass()) {
                return false;
            }
            final UserScoring other = (UserScoring) obj;

            return user.equals(other.user);
        }
    }

I want to create a class UserScoring which can be sorted on the basis of its variable score and whose uniqueness is determined by its user.

This means that :

  1. If I sort a collection of UserScoring objects using Collections.sort(), I want the sorting based on score in a descending order. I have overriden the compareTo method for the same.
  2. If I create a set of the UserScoring objects, I do not want two UserScoring objects of the same user. I have overriden the equals and the hashcode method for the same.

I have two doubts here: 1. Is it wrong to return the hashcode of the UserScoring object the same as the User object. It sure looks wrong to me. But what are the problems it can cause?

  1. Is there any way at all to make sure that only the UserScoring object of the higher score is kept in the set(and the object with less score is either evicted or not added) whenever there is an attempt to add two UserScoring objects of the same user.

    UserScoring us1 = new UserScoring(u1, 1000);
    UserScoring us2 = new UserScoring(u1, 100);
    Set<UserScoring> set = new HashSet<>();
    set.add(us1);
    set.add(us2);
    

How can this set contain us1 instead of us2?

12
  • 2
    hashCode and equals implementations have to match each other. Yours do not. Commented Apr 10, 2017 at 7:48
  • 1
    @OliverCharlesworth In what sense do they have to match? What can I do here so they match? Commented Apr 10, 2017 at 7:49
  • 1
    @OliverCharlesworth In what way to the hashCode() and equals() implementations not match? They're both just considering the user field. What doesn't match up is the compareTo implementation. Commented Apr 10, 2017 at 7:58
  • 1
    @tanvi That you could have two objects that your equals method says are equal, but compareTo between them will not return 0. Your compareTo is not consistent with equality. Commented Apr 10, 2017 at 8:02
  • 1
    @tanvi I think you might be better off with a Map<User, UserScoring>. That way you can look up the UserScoring based on a User; have only one UserScoring per User; and you can explicitly keep the one with the higher score if that is what you want. Currently you are trying to use equals to group objects that you don't really consider equal. Commented Apr 10, 2017 at 8:07

1 Answer 1

1
  1. Is it wrong to return the hashcode of the UserScoring object the same as the User object. It sure looks wrong to me. But what are the problems it can cause?

It is not wrong. In this case, we say that the "identity" of the UserScoring object is the associated User object. However, this requires that your equals() method must also honor this identity convention, so it must be implemented as return Objects.equal( this.user, other.user ).

  1. Is there any way at all to make sure that the UserScoring object of the higher score is kept in the set whenever there is an attempt to add two UserScoring objects of the same user.

I do not think there is any way to automate this with an unmodified HashSet, but you can provide your own Set decorator (call it, say, RankingSet) which examines the object being added against the object already in the underlying Set and keeps the one with the higher rank. (The rank in your case being the score.) You can look around the interwebz for a CollectionDecorator that you can use to reduce the amount of work that you need to do: it will enable you to only override the add() method and let the rest of the methods be delegated to the underlying Set

Since you need to be able to compare your UserScoring objects, another problem you are likely to run into is that your equals() method does not agree with the result returned by Comparable.compareTo(). One way to overcome this is by not making UserScoring comparable, and instead implementing a separate Comparator which compares UserScoring objects based on their score.

(So, the RankingSet would need to receive such a Comparator as a constructor parameter.)

Sign up to request clarification or add additional context in comments.

3 Comments

Thanks a lot Mike. This helps. I want to rephrase my question 2 "Is there any way at all to make sure that the UserScoring object of the higher score is kept in the set AND THE ONE WITH LESSER SCORE IS REMOVED whenever there is an attempt to add two UserScoring objects of the same user." I don't want to keep two objects with same user.
I see. I do not think there is any way to automate this with an unmodified HashSet, but you can provide your own RankingSet decorator which examines the object being added against the object already in the underlying Set and keeps the one with the higher rank. (The rank being determined by a supplied Comparator.) You can look around the interwebz for a CollectionDecorator that you can use to reduce the amount of work that you need to do: it will enable you to only override the add() method and let the rest of the methods be delegated to the underlying Set.
I have heard about the decorator pattern but not used it. Thanks a ton @Mike. I will look this up.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.