Closed. This question needs debugging details. It is not currently accepting answers.
Edit the question to include desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem. This will help others answer the question.
Closed 7 years ago.
Improve this question
There is something that escapes me about hashCode. I know that if i override
equals, then i must override hashCode too. I also know that if two objects are
equal, then the hashCode of the two objects must be equal. If the fields that are checked in the equals method don't change, than the hashCode should not change, right?
If so, then i can't understand why each time i create an instance of the object below, i get a different hashCode:
public class Effect {
private long timestamp;
private int damage;
private SquareType squareType;
public Effect(long timestamp, int damage, SquareType squareType) {
this.timestamp = timestamp;
this.damage = damage;
this.squareType = squareType;
}
public long getTimestamp() {
return timestamp;
}
public int getDamage() {
return damage;
}
public SquareType getSquareType() {
return squareType;
}
#Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
Effect effect = (Effect) o;
if (getDamage() != effect.getDamage()) return false;
return getSquareType() == effect.getSquareType();
}
#Override
public int hashCode() {
int result = getDamage();
result = 31 * result + (getSquareType() != null ? getSquareType().hashCode() : 0);
return result;
}
#Override
public String toString() {
String ret = "Effect hashcode: " + hashCode();
return ret;
}
}
In the code i create this kind of objects continuously over time. The only field that changes each time is "timestamp", but the two other fields don't change (unless there is a specific event). What happens is that the hashCode value is always different, even if "damage" and "SquareType" are the same.
I don't use "timestamp" in my equals and hashCode, so i can't understand why i get this behavior.
Update
This is SquareType:
public enum SquareType {
FIRE, WIND, WATER, EARTH
}
Update 2
For example, if i create 10 instances of Effect, i iterate over them and i
print them (toString() returns the hashCode value) i get 10 different values.
If two instances of Effect have the same "damage" and "SquareType" then they must be equal and have the same hashCode.
Update 3
The effects are created like this:
#Override
public void friendlyFire(BaseBullet bullet, BaseSquare square) {
square.notifyFriendlyFire(new Effect(TimeUtils.millis(),
square.getDamage(), square.getSquareType()), new MyKey(square.getUniqueID()));
}
The only Effect's field that changes is the timestamp, and i don't use it in equals and hashCode.
public void notifyFriendlyFire(Effect newEffect, MyKey key) {
// System.out.println("The map contains the key? " + effectMap.containsKey(key));
if(effectMap.containsKey(key)) {
Effect oldEffect = effectMap.get(key);
System.out.println(newEffect);
if(!oldEffect.equals(newEffect)) {
System.out.println("old effect changed!");
// remove the old effect
removeEffect(oldEffect);
// update the map with the new effect
effectMap.put(key, newEffect); //
// apply the new effect
applyEffect(newEffect);
}
}
else {
// new effect
effectMap.put(key, newEffect);
applyEffect(newEffect);
}
}
The check "if(!oldEffect.equals(newEffect))" is always true, even if damage and type are the same.
Update 4
I've found the bug. Damage increases continuously. Now i've just to figure out why...
Here's my attempt at approximating your implementation:
package cruft;
import java.util.Date;
/**
* Equals and hashCode test
* Creation date 1/16/2016.
* #link https://stackoverflow.com/questions/34826585/hashcode-changes-each-time-the-object-is-created
*/
public class OverrideDemo {
private long timestamp;
private int damage;
private SquareType squareType;
public OverrideDemo(int damage, SquareType squareType) {
this(damage, squareType, new Date().getTime());
}
public OverrideDemo(int damage, SquareType squareType, long timestamp) {
if (squareType == null) throw new IllegalArgumentException("square type cannot be null");
this.timestamp = timestamp;
this.damage = damage;
this.squareType = squareType;
}
public long getTimestamp() {
return timestamp;
}
public int getDamage() {
return damage;
}
public SquareType getSquareType() {
return squareType;
}
#Override
public boolean equals(Object o) {
if (this == o) { return true; }
if (o == null || getClass() != o.getClass()) { return false; }
OverrideDemo that = (OverrideDemo) o;
if (damage != that.damage) { return false; }
return squareType == that.squareType;
}
#Override
public int hashCode() {
int result = damage;
result = 31 * result + squareType.hashCode();
return result;
}
#Override
public String toString() {
return "OverrideDemo{" +
"timestamp=" + timestamp +
", damage=" + damage +
", squareType=" + squareType +
'}';
}
}
enum SquareType { FIRE, WIND, WATER, EARTH }
Here's a Junit test that shows how the methods behave. All tests pass; I think this implementation is correct.
package cruft;
import org.junit.Assert;
import org.junit.Test;
/**
* Junit test demonstrates testing equals and hashcode contract
* Created by Michael
* Creation date 1/16/2016.
* #link https://stackoverflow.com/questions/34826585/hashcode-changes-each-time-the-object-is-created
*/
public class OverrideDemoTest {
#Test
public void testEquals_Null() {
OverrideDemo x = new OverrideDemo(5, SquareType.EARTH);
Assert.assertFalse(x.equals(null));
}
#Test
public void testEquals_Reflexive() {
OverrideDemo x = new OverrideDemo(5, SquareType.EARTH);
Assert.assertTrue(x.equals(x));
}
#Test
public void testEquals_Symmetric() {
OverrideDemo x = new OverrideDemo(5, SquareType.EARTH);
OverrideDemo y = new OverrideDemo(5, SquareType.EARTH);
Assert.assertTrue(x.equals(y));
Assert.assertTrue(y.equals(x));
Assert.assertTrue(x.hashCode() == y.hashCode());
}
#Test
public void testEquals_Transitive() {
OverrideDemo x = new OverrideDemo(5, SquareType.EARTH);
OverrideDemo y = new OverrideDemo(5, SquareType.EARTH);
OverrideDemo z = new OverrideDemo(5, SquareType.EARTH);
Assert.assertTrue(x.equals(y));
Assert.assertTrue(y.equals(z));
Assert.assertTrue(z.equals(x));
Assert.assertTrue(x.hashCode() == y.hashCode());
Assert.assertTrue(y.hashCode() == z.hashCode());
Assert.assertTrue(z.hashCode() == x.hashCode());
}
#Test
public void testEquals_DifferentDamage_NotEqual() {
OverrideDemo x = new OverrideDemo(5, SquareType.EARTH);
OverrideDemo y = new OverrideDemo(10, SquareType.EARTH);
Assert.assertFalse(x.equals(y));
Assert.assertFalse(y.equals(x));
Assert.assertFalse(x.hashCode() == y.hashCode());
}
#Test
public void testEquals_DifferentSquareType_NotEqual() {
OverrideDemo x = new OverrideDemo(10, SquareType.EARTH);
OverrideDemo y = new OverrideDemo(10, SquareType.FIRE);
Assert.assertFalse(x.equals(y));
Assert.assertFalse(y.equals(x));
Assert.assertFalse(x.hashCode() == y.hashCode());
}
}
Related
I am working on a dummy hospital database. I have an ArrayList that has the combination of all possible times that a doctor can theoretically hold an appointment, and another ArrayList that holds actual registered appointments.
Availability {
int doctorid;
String specialty;
Date date;
int order_of_appointment;
}
//////////
ArrayList<Availability> allTimes;
ArrayList<Availability> busyTimes;
What I want to accomplish is finding the times where doctors are free. Which is the result of (allTimes - busyTimes)
I tried using allTimes.removeAll(busyTimes) but it didn't remove anything.
I made sure that I am overriding the equals() method in the Availability class but it still doesn't remove anything.
#Override
public boolean equals(Object o) {
if (this == o) return true;
if (!(o instanceof Availability)) return false;
Availability that = (Availability) o;
return doctorid == that.doctorid &&
order_of_appointment == that.order_of_appointment &&
Objects.equals(specialty, that.specialty) &&
Objects.equals(date, that.date);
}
Output:
busyTimes =
[Availability{doctorid=1, specialty='internal medicine', date=2021-11-02, order_of_appointment=2}
]
allTimes =
[Availability{doctorid=1, specialty='internal medicine', date=2021-11-02, order_of_appointment=1}
, Availability{doctorid=1, specialty='internal medicine', date=2021-11-02, order_of_appointment=2}
, Availability{doctorid=1, specialty='internal medicine', date=2021-11-02, order_of_appointment=3}]
The output I get for freeTimes is identical to allTimes even though I'm expecting it to remove the appointment with order_of_appointment==2.
I am totally clueless on what might be causing this. Any help would be appreciated. Thanks in advance!
You don't show how are you creating the array, or how are you adding the elements.
I did a simple program with ArrayLists and works as expected:
import java.util.*;
class A {
int id;
A(int id) {
this.id = id;
}
#Override
public boolean equals(Object o) {
return o instanceof A && this.id == ((A)o).id;
}
public String toString() {
return String.format("A{id:%s}", id);
}
public static void main(String ... args) {
List<A> a = new ArrayList<A>(Arrays.asList(new A(1), new A(2)));
List<A> b = new ArrayList<A>(Arrays.asList(new A(2), new A(3)));
a.removeAll(b);
System.out.println(a);
}
}
Output:
[A{id:1}]
What was wrong is that even though I had the date format set up as "yyyy-MM-dd", it still stored the time inside the Date object. I converted the Date objects to strings and then compared the strings and that worked. Thank you all.
You need to override equals(Object obj) method in Availability class with your comparison logic.
I implemented it. please check.
import java.util.Date;
public class Availability {
private int doctorId;
private String specialty;
private Date date;
private int orderOfAppointment;
public Availability() {
super();
}
public Availability(int doctorId, String specialty, Date date, int orderOfAppointment) {
super();
this.doctorId = doctorId;
this.specialty = specialty;
this.date = date;
this.orderOfAppointment = orderOfAppointment;
}
public int getDoctorId() {
return doctorId;
}
public void setDoctorId(int doctorId) {
this.doctorId = doctorId;
}
public String getSpecialty() {
return specialty;
}
public void setSpecialty(String specialty) {
this.specialty = specialty;
}
public Date getDate() {
return date;
}
public void setDate(Date date) {
this.date = date;
}
public int getOrderOfAppointment() {
return orderOfAppointment;
}
public void setOrderOfAppointment(int orderOfAppointment) {
this.orderOfAppointment = orderOfAppointment;
}
#Override
public String toString() {
return "Availability [doctorId=" + doctorId + ", specialty=" + specialty + ", date=" + date
+ ", orderOfAppointment=" + orderOfAppointment + "]";
}
#Override
public boolean equals(Object obj) {
boolean returnVal = false;
Availability busyslote = (Availability) obj;
if (this.doctorId == busyslote.doctorId && this.orderOfAppointment == busyslote.orderOfAppointment
&& this.specialty.equalsIgnoreCase(busyslote.specialty) && this.date.equals(busyslote.date)) {
returnVal = true;
} else {
returnVal = false;
}
return returnVal;
}
}
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
public class AppointmentMain {
public static void main(String[] args) {
List<Availability> allAppointment = new ArrayList<>();
List<Availability> attenedAppointment = new ArrayList<>();
Availability obj1 = new Availability(1, "Internal Medicine", new Date(), 1);
Availability obj2 = new Availability(1, "Internal Medicine", new Date(), 2);
Availability obj3 = new Availability(1, "Internal Medicine", new Date(), 3);
allAppointment.add(obj1);
allAppointment.add(obj2);
allAppointment.add(obj3);
Availability obj4 = new Availability(1, "Internal Medicine", new Date(), 3);
attenedAppointment.add(obj4);
System.out.println("Befour count :" + allAppointment.size());
allAppointment.removeAll(attenedAppointment);
System.out.println("After count :" + allAppointment.size());
}
}
I'm trying to count the number of diseases a day by using hashmap:
public static main(String[] args){
Disease cholera=new Disease("cholera");
Disease dengue=new Disease("dengue");
List<Diagnosis> diagnoses = Arrays.asList(
new Diagnosis(cholera, 0), // registered cholera on day 0
new Diagnosis(cholera, 0),
new Diagnosis(cholera, 1),
new Diagnosis(cholera, 1),
new Diagnosis(cholera, 2),
new Diagnosis(cholera, 2)
);
printFreq(diagnosis);
}
public static void printFreq(List<Diagnosis> diagnoses) {
Map<Diagnosis, Integer> hm = new HashMap();
for (Diagnosis x : diagnoses) {
if (!hm.containsKey(x)) {
hm.put(x, 1);
} else {
hm.put(x, hm.get(x) + 1);
}
}
But if I call printFreq(diagnoses) I get:{{cholera, 0}=1, {cholera, 1}=1, {cholera, 2}=1, {cholera, 0}=1, {dengue, 0}=1, {cholera, 1}=1, {cholera, 2}=1}. How can I fix this to {{cholera,0}=2,{dengue0}=1,{cholera,1}=2,{cholera,2}=2}}
I'm not allowed to change the Diagnosis or Disease class but this is how they look like:
public class Disease {
private final String name;
public Disease(String name) {
this.name = name;
}
public String getName() {
return name;
}
#Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
Disease disease = (Disease) o;
return name.equals(disease.name);
}
#Override
public int hashCode() {
return name.hashCode();
}
#Override
public String toString() {
return name;
}
Diagnosis:
public class Diagnosis {
private final Disease disease;
private final int day;
public Diagnosis(Disease disease, int day) {
this.disease = disease;
this.day = day;
}
public Disease getDisease() {
return disease;
}
public int getDay() {
return day;
}
#Override
public String toString() {
return "{" + disease + ", " + day + "}";
}
You can add a wrapper class to make life easier. In this code I have a wrapper class DiagnosisMetric that wraps the Diagnosis class.
Following is the new implementation of the printFreq function.
public static void printFreq(List<Diagnosis> diagnoses) {
Map<DiagnosisMetric, Long> collect = diagnoses.stream().
collect(Collectors.groupingBy(DiagnosisMetric::new, counting()));
System.out.println(collect);
}
And, following is the wrapper class. Notice that I have implemented equals and hashCode as per the requirement.
public static class DiagnosisMetric {
private Diagnosis diagnosis;
public DiagnosisMetric(Diagnosis s) {
this.diagnosis = s;
}
public Diagnosis getDiagnosis() {
return diagnosis;
}
#Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
DiagnosisMetric that = (DiagnosisMetric) o;
return diagnosis.getDisease().getName().
equals(that.getDiagnosis().getDisease().getName())
&& diagnosis.getDay() == that.getDiagnosis().getDay();
}
#Override
public int hashCode() {
return Objects.hash(diagnosis.getDay(),
diagnosis.getDisease().getName());
}
#Override
public String toString() {
String disease = diagnosis.getDisease().getName();
int day = diagnosis.getDay();
return "{" + disease + ", " + day + "}";
}
}
An ad-hoc solution which does not require storing the intermediate map with Diagnosis key (which cannot be used as a map key without properly implemented hashCode and equals as mentioned earlier) is like this:
use a raw list containing diagnosis.day and disease.name as a key wrapper in Collectors.groupingBy
calculate the frequencies (e.g. using Collectors.summingInt)
use Supplier<Map> to provide a tree map sorted by the list contents
print the stats
diagnoses.stream()
.collect(Collectors.groupingBy(
d -> Arrays.asList(d.getDay(), d.getDisease().getName()),
() -> new TreeMap<List<?>, Integer> (Comparator
.comparingInt((List k) -> (Integer) k.get(0))
.thenComparing((List k) -> (String) k.get(1))
),
Collectors.summingInt(d -> 1)
)) // Map<List, Integer> created here
.forEach((k, v) -> System.out.println(k + " = " + v));
Output:
[0, cholera] = 2
[0, dengue] = 1
[1, cholera] = 2
[2, cholera] = 2
To resolve this what we need to do is to override the hashCode and equals method for the Diagnosis class, like this:
#Override
public boolean equals(Object obj) {
Diagnosis diagnosis = (Diagnosis) obj;
return this.day == diagnosis.day && this.disease == diagnosis.disease;
}
#Override
public int hashCode() {
char[] charArr = this.disease.toString().toCharArray();
int sum = 0;
for (int i = 0; i < charArr.length; i++) {
sum += charArr[i];
}
return sum;
}
Also you need to override equals method of the Disease class, here is code for that:
#Override
public boolean equals(Object obj) {
Disease disease = (Disease) obj;
return this.disease.equalsIgnoreCase(disease.toString());
}
What I am trying to do here is to fill a HashMap with objects Obj using the key Key and when I finish I want to have access to those values according to any any of the possible keys. I have written the following code and what happened is that although the first show really shows the values I want, the second one raises a NullPointerException.
import java.util.*;
public class My{
public static void main(String[] args){
Map<Key,Obj> myMap = new HashMap<Key,Obj>();
Obj ob1 = new Obj("Nick",19);
Obj ob2 = new Obj("George",17);
Key key1 = new Key(1,2);
Key key2 = new Key(2,1);
myMap.put(key1,ob1);
myMap.put(key2,ob2);
myMap.get(key1).show();
myMap.get(new Key(1,2)).show();
}
I can tell that somehow Java cannot tell that new Key(1,2) is equal with key1, but I cannot think of how can I overcome this issue.
public class Obj{
private String name;
private int age;
Obj(String name, int age){
this.name = name;
this.age = age;
}
public void show(){
System.out.println(name + " " + age);
}
}
These are the classes I use
import java.* ;
public class Key{
public int x,y;
Key(int x, int y){
this.x = x;
this.y = y;
}
public boolean equals(Key d){
if ((this.x == d.x)&&(this.y == d.y)){
return true;
}
else{
return false;
}
}
}
You have two problems in your implementation of Key. First, the equals' method signature is wrong - it should be public boolean equals(Object). This error would have been easily noticeable if you had used the #Override annotation. Second, you should also override the hashCode() method:
#Override
public boolean equals(Object o) {
if (o == null || getClass() != o.getClass()) {
return false;
}
Key key = (Key) o;
return x == key.x && y == key.y;
}
#Override
public int hashCode() {
return Objects.hash(x, y);
}
So I'm working on a very basic code which implements Comparable comparing a painting based on year, artist and title.
However my code isn't comparing the paintings by title, just year and artist.
public class Main {
/**
* #param args the command line arguments
*/
public static void main(String[] args) {
// TODO code application logic here
Painting p1 = new Painting(Year.NINETYEIGHT, artist.ART1, title.TIT1);
Painting p2 = new Painting(Year.NINETYEIGHT, artist.ART1, title.TIT2);
System.out.println("p1: " + p1.toString());
System.out.println("p2: " + p2.toString());
if(p1.compareTo(p2)> 0){
System.out.println(p1.toString() + " beats " + p2.toString());
} else if(p1.compareTo(p2) < 0){
System.out.println(p2.toString() + " beats " + p1.toString());
} else{
System.out.println("Same Everything");
}
}
}
public enum Year {
NINETYSEVEN, NINETYEIGHT, NINETYNINE, TWOTHOUSAND
}
public enum artist {
ART1, ART2, ART3,
}
public enum title {
TIT1, TIT2,TIT3,
}
public class Painting implements Comparable {
private title title;
private Year year;
private artist artist;
public Painting(Year y, artist a, title t) {
title = t;
year = y;
artist = a;
}
#Override
public int compareTo(Object o) {
//compare values
Painting other = (Painting) o;
int yearCompare = this.year.compareTo(other.year);
int artistCompare = this.artist.compareTo(other.artist);
if (yearCompare == 0) {
//same year, compare artist
return this.artist.compareTo(other.artist);
} else if (artistCompare == 0) {
return this.title.compareTo(other.title);
} else {
return yearCompare;
}
}
#Override
public String toString() {
return title.name() + " by " + artist.name() + " produced " + year.name();
}
}
Dang. Slow by just a few seconds. Haha. I came up with the same solution as shmosel.
public int compareTo(Painting other) {
int yearCompare = year.compareTo(other.year);
if (yearCompare != 0)
return yearCompare;
int artistCompare = artist.compareTo(other.artist);
if (artistCompare != 0)
return artistCompare;
return title.compareTo(other.title);
}
One difference. I would consider changing your class header. Specifically, I would change:
public class Painting implements Comparable
to:
public class Painting implements Comparable<Painting>
This way, instead of using the "raw" Object type, you're Painting class's compareTo() method signature will become:
public int compareTo(Painting o)
In other words, you don't have to cast or worry about checking if an argument is an instance of Painting!
Your if-else logic is flawed in several ways. It should more look like this:
int yearCompare = this.year.compareTo(other.year);
if (yearCompare != 0) {
return yearCompare;
}
int artistCompare = this.artist.compareTo(other.artist);
if (artistCompare != 0) {
return artistCompare;
}
return this.title.compareTo(other.title);
On a side note, you should generics and avoid casting:
public class Painting implements Comparable<Painting> {
#Override
public int compareTo(Painting other) {
// no casting necessary
}
}
Output of below class is :
size is 3
size is 1
But if I change the TreeSet to a HashSet so line :
Set<SuggestionDetailBean> set = new TreeSet<SuggestionDetailBean>();
becomes
Set<SuggestionDetailBean> set = new HashSet<SuggestionDetailBean>();
the output is :
size is 3
size is 2
Shout using HashSet or TreeSet not change the size of Set ?
Using HashSet seems to behave as expected because it is removing duplicates but when I use TreeSet the duplicates remain ?
I think the hashcode and equals methods in SuggestionDetailBean are overriden correctly ?
Here is the code :
public class TestSet {
public static void main(String args[]){
SuggestionDetailBean s = new SuggestionDetailBean();
s.setTagList("teddst");
s.setUrl("testurl");
SuggestionDetailBean s2 = new SuggestionDetailBean();
s2.setTagList("teddst");
s2.setUrl("testurl");
SuggestionDetailBean s3 = new SuggestionDetailBean();
s3.setTagList("tessdafat");
s3.setUrl("fdfaasdfredtestur ldd");
List<SuggestionDetailBean> list = new ArrayList<SuggestionDetailBean>();
list.add(s);
list.add(s2);
list.add(s3);
Set<SuggestionDetailBean> set = new TreeSet<SuggestionDetailBean>();
set.addAll(list);
System.out.println("size is "+list.size());
System.out.println("size is "+set.size());
}
}
public class SuggestionDetailBean implements Comparable<Object> {
private String url;
private String tagList;
private String numberOfRecommendations;
private String date;
private String time;
private String summary;
private String truncatedUrl;
public void setTruncatedUrl(String truncatedUrl) {
if(truncatedUrl.length() > 20){
truncatedUrl = truncatedUrl.substring(0, 20)+"...";
}
this.truncatedUrl = truncatedUrl;
}
public String getSummary() {
if(summary == null){
return "";
}
else {
return summary;
}
}
public void setSummary(String summary) {
this.summary = summary;
}
public String getDate() {
return date;
}
public void setDate(String date) {
this.date = date;
}
public String getTime() {
return time;
}
public String getTruncatedUrl() {
return this.truncatedUrl;
}
public void setTime(String time) {
this.time = time;
}
public String getTagList() {
if(tagList == null){
return "";
}
else {
return tagList;
}
}
public void setTagList(String tagList) {
this.tagList = tagList;
}
public String getUrl() {
return url;
}
public void setUrl(String url) {
this.url = url;
}
public String getNumberOfRecommendations() {
return numberOfRecommendations;
}
public void setNumberOfRecommendations(String numberOfRecommendations) {
this.numberOfRecommendations = numberOfRecommendations;
}
#Override
public int compareTo(Object o) {
DateFormat formatter;
Date date1 = null;
Date date2 = null;
SuggestionDetailBean other = (SuggestionDetailBean) o;
if(this.date == null || other.date == null){
return 0;
}
formatter = new SimpleDateFormat(SimpleDateFormatEnum.DATE.getSdfType()+" "+SimpleDateFormatEnum.TIME.getSdfType());
try {
date1 = (Date) formatter.parse(this.date + " " + this.time);
date2 = (Date) formatter.parse(other.date + " " + other.time);
} catch (ParseException e) {
System.out.println("Exception thrown in"+this.getClass().getName()+", compareTo method");
e.printStackTrace();
}
catch(NullPointerException npe){
System.out.println("Exception thrown "+npe.getMessage()+" date1 is "+date1+" date2 is "+date2);
}
return date2.compareTo(date1);
}
#Override
public int hashCode() {
return this.url.hashCode();
}
#Override
public boolean equals(Object obj) {
SuggestionDetailBean suggestionDetailBean = (SuggestionDetailBean) obj;
if(StringUtils.isEmpty(this.getTagList())){
return this.getUrl().equals(suggestionDetailBean.getUrl());
}
else {
return (this.getTagList().equals(suggestionDetailBean.getTagList())) &&
(this.getUrl().equals(suggestionDetailBean.getUrl()));
}
}
}
Edit :
Note : if I convert the hashset to a treeset using :
Set<SuggestionDetailBean> sortedSet = new TreeSet<SuggestionDetailBean>(hashset);
Then correct sorting is maintained, as the removal of duplicates is based on the object hashcode and equals methods not the compareto method.
According to the Javadoc for TreeSet:
Note that the ordering maintained by a set (whether or not an explicit
comparator is provided) must be consistent with equals if it is to
correctly implement the Set interface. (See Comparable
or Comparator for a precise definition of consistent with
equals.) This is so because the Set interface is defined in
terms of the equals operation, but a TreeSet instance
performs all element comparisons using its compareTo (or
compare) method, so two elements that are deemed equal by this method
are, from the standpoint of the set, equal. The behavior of a set
is well-defined even if its ordering is inconsistent with equals; it
just fails to obey the general contract of the Set interface.
So, the problem is with your compareTo method: either it's giving inconsistent results, or else it's giving consistent results that don't obey the rule that a.compareTo(b) == 0 if and only if a.equals(b).
For example, this bit:
if(this.date == null || other.date == null){
return 0;
}
means "if either this or other has date == null, then report that this and other are equal", which is certainly not what you want.