0

I know this has been asked several times and I promise I have read over 100 articles before resorting to posting. Here is my issue:

  1. I have created my own object (WorkoutData). It is made up of several string variables, and integer and a linked list of strings:

    public class WorkoutData implements Serializable {
        private static final long serialVersionUID = 878893767880469289L;
        String workoutLocation;
        String bodyPart;
        String exercise;
        int numOfSets;
        LinkedList<LinkedList<String>> datesSetsAndReps;
    }
    
  2. In case any duplicates ever get into my datafile I am reading the objects into a LinkedHashSet. My thinking is that this will automatically eliminate any duplicates.

Of course this isn't working, because each object has its own ID and therefore will not be "equal" to another object. To try to get around this I have overridden the equals and hashCode inside my WorkoutData class.

For some reason it is still not working. Here is how I am loading my linkedHashSet:

for (int iterator = 0; iterator < numberOfWorkouts; iterator++)
    tempWorkoutDataSet.add((WorkoutData) in.readObject());

Here are my overridden methods in the WorkoutData class:

@Override
public boolean equals(Object other)
{
    if (other == null)
    {
        return false;
    }

    if (this.getClass() != other.getClass())
    {
        return false;
    }

    if (!this.workoutLocation.equals(((WorkoutData)other).workoutLocation))
    {
        return false;
    }

    if (!this.bodyPart.equals(((WorkoutData)other).bodyPart))
    {
        return false;
    }

    if (!this.exercise.equals(((WorkoutData)other).exercise))
    {
        return false;
    }

    return true;
}

public int hashCode()
{
    return this.workoutLocation.length();
}

The hashset contains duplicates no matter what I try. I think the equals method is correct, but I freely admit I have no idea what the hashCode method is meant to accomplish.

This question is NOT a duplicate of "How do I compare strings in Java?". That question only talks about the == vs .equals issue. My issue has more to do with overriding hashCode. I think that is where my problem lies. Couple that with the fact that I am still unclear exactly what the hashCode override is meant to accomplish.

UFGator
  • 55
  • 7
  • `if (this.bodyPart != ((WorkoutData)other).bodyPart)` should be `if (this.bodyPart.equals(((WorkoutData)other).bodyPart))` same thing for the other `Strings` use .equals when comparing `Strings` or `.equalsIgnoreCase()` – brso05 May 11 '15 at 20:31
  • I suspect that hashCode implementation is not what you want, either. – spudone May 11 '15 at 20:39
  • You overrode the `equals` method instead of incorrectly using `==`, but in it you incorrectly use `==` instead of using `equals`. Also, consider overriding `toString` to return something something like "location: blah, bodyPart: blah, exercise: blah" etc. and having your `hashCode` be `public int hashCode() { return toString().hashCode(); }`. – Captain Man May 11 '15 at 20:50
  • brso05 - Thanks. That's a good point. I have eliminated the != in lieu of the .equals. – UFGator May 11 '15 at 21:27
  • Captain Man - Thanks for the response. As previously noted I have changed from != to .equals. I have overridden toString already. Why would toString().hasCode() be better than what I have now? Thanks for helping. – UFGator May 11 '15 at 21:29
  • Even with != changed to .equals, duplicates are still loaded into the hashSet. I believe that the problem might be with the hashCode override. – UFGator May 11 '15 at 21:45
  • 2
    Your hashcode method makes absolutly no sense to me. Why should two instance with the same `workoutLocation` length produce the same hash code if they are not equal, because for example they have different body parts. What have you read about overriding `equals` and `hashCode`? I hope it is not "nothing". Btw, please read this: [What issues should be considered when overriding equals and hashCode in Java?](http://stackoverflow.com/q/27581) – Tom May 11 '15 at 21:50
  • 1
    You incorrectly switched `!=` to `.equals` you need to do `!(...).equals(...)` – chancea May 11 '15 at 21:55
  • Chancea - Yes. Thanks. I did it correctly in the code but forgot the ! above. Thanks! – UFGator May 12 '15 at 22:33
  • Tom - Thanks for the reply. I agree that my hashCode implementation is worthless. I have read everything I can get my hands on regarding hashCode and quite frankly they give many examples, but not the underlying logic. I freely admit I don't understand it. I'm hoping the article you referred me to will help. I will read it and update. – UFGator May 12 '15 at 23:10
  • Thank you all that have helped me on this. The code is now working. Duplicates are not being loaded into the linkedHashSet. As pointed out by Tom, my override of hashCode is worthless. I am going to research the link provided and update with my findings. Anyone with any ideas on an appropriate way to override hashCode would be greatly appreciated. – UFGator May 12 '15 at 23:22
  • 1
    With further research I have changed my hashCode override to be: `return (this.workoutLocation.length())+(this.bodyPart.length())+(this.exercise.length());` – UFGator May 13 '15 at 02:52
  • @UFGator Glad it helped. I voted for reopening your question. If that happens, you can answer your question by pointing out what you've changed and why you did that. So other users/readers with the same question can learn from your answer. – Tom May 13 '15 at 17:42
  • I've reopened this question because of the changes. – rgettman May 13 '15 at 19:19
  • Do you really need to retain the order of `in.readObject()` or do you just want to remove duplicates? Basically it sounds like you just shouldn't use `equals` to do this. (Because the only way to fix it is to use an implementation of `equals` which doesn't compare IDs.) – Radiodef May 13 '15 at 19:25
  • Hi Radiodef - I don't really need to retain the order. I just want to remove duplicates. It would seem that an override of `equals` is an efficient way of doing this. Perhaps I am missing something. – UFGator May 14 '15 at 02:06

1 Answers1

0

Thanks to all the great help out there I was able to resolve the question. It amounted to two basic issue:

  1. Overriding the equals (as opposed to trying ==) was the right thing to do to keep duplicates from being added to the hashSet. Since objects have numeric identifiers == will not work and you have to use equals. If equals is not overriden then hashSet will use the system supplied equals which pretty much acts the same as ==. The problem was the very thing I was trying to get away from using in my base code, ==, I mistakenly used in the equals override in the object class file. Once I changed the equals override to use !equals (as shown above) instead of != the code worked as planned.

  2. Overriding the hashCode was also important. My override was useless because it returned a value that would NOT be unique in all (or most) cases. Following some of the help links provided I configured a hashCode override methodology that used the same logic as the equals override, as suggested. This is also shown above. Note how the same 3 parameters of the object used in the equals override are also used in the hashCode override.

Now the code works fine. The concept of overriding equals and hashCode for objects in a hashSet is complicated at first, but seems rather easy upon reflection. Thanks again for all the great help!

UFGator
  • 55
  • 7