Reputation: 10551
I have a class Product, which three variables:
class Product implements Comparable<Product>{
private Type type; // Type is an enum
Set<Attribute> attributes; // Attribute is a regular class
ProductName name; // ProductName is another enum
}
I used Eclipse to automatically generate the equal() and hashcode() methods:
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + ((attributes == null) ? 0 : attributes.hashCode());
result = prime * result + ((type == null) ? 0 : type.hashCode());
return result;
}
@Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
Product other = (Product) obj;
if (attributes == null) {
if (other.attributes != null)
return false;
} else if (!attributes.equals(other.attributes))
return false;
if (type != other.type)
return false;
return true;
}
Now in my application I need to sort a Set of Product, so I need to implement the Comparable interface and compareTo method:
@Override
public int compareTo(Product other){
int diff = type.hashCode() - other.getType().hashCode();
if (diff > 0) {
return 1;
} else if (diff < 0) {
return -1;
}
diff = attributes.hashCode() - other.getAttributes().hashCode();
if (diff > 0) {
return 1;
} else if (diff < 0) {
return -1;
}
return 0;
}
Does this implementation make sense? What about if I just want to sort the product based on the String values of "type" and "attributes" values. So how to implement this?
Edit: The reason I want to sort a Set of is because I have Junit test which asserts on the string values of a HashSet. My goal is to maintain the same order of output as I sort the set. otherwise, even if the Set's values are the same, the assertion will fail due to random output of a set.
Edit2: Through the discussion, it's clear that to assert the equality of String values of a HashSet isn't good in unit tests. For my situation I currently write a sort() function to sort the HashSet String values in natural ordering, so it can consistently output the same String value for my unit tests and that suffice for now. Thanks all.
Upvotes: 0
Views: 2563
Reputation: 5948
Looks like from all the comments in here you dont need to use Comparator
at all. Because:
1) You are using HashSet
that does not work with Comparator
. It is not ordered.
2) You just need to make sure that two HashSet
s containing Product
s are equal. It means they are same size and contain the same set of Product
s.
Since you already added hashCode
and equals
methods to Product
all you need to do is call equals
method on those HashSet
s.
HashSet<Product> set1 = ...
HashSet<Product> set2 = ...
assertTrue( set1.equals(set2) );
Upvotes: 1
Reputation: 25903
This implementation does not seem to be consistent. You have no control over how the hash codes
look like. If you have obj1 < obj2
according to compareTo
in the first try, the next time you start your JVM
it could be the other way around obj1 > obj2
.
The only thing that you really know is that if diff == 0
then the objects are considered to be equal. However you can also just use the equals
method for that check.
It is now up to you how you define when obj1 < obj2
or obj1 > obj2
. Just make sure that it is consistent.
By the way, you know that the current implementation does not include ProductName name
in the equals
check? Dont know if that is intended thus the remark.
The question is, what do you know about that attributes? Maybe they implement Comparable
(for example if they are Number
s), then you can order according to their compareTo
method. If you totally know nothing about the objects, it will be hard to build up a consistent ordering.
If you just want them to be ordered consistently but the ordering itself does not play any role, you could just give them id
s at creation time and sort by them. At this point you could indeed use the hashcodes if it does not matter that it can change between JVM
calls, but only then.
Upvotes: 0