Comparable vs. Comparator
You should favor the Comparator-interface over the Comparable-interface.
Comparision of two objects is always context specific. If you implement the Comparable-interface your class is bound to the context you defined. If you change the comparison you have to check every single usage semantically to ensure no side effects.
I prefer using the Comparator-interface to define context specific comparison without taking the burden on the class to compare. If I want to provide one or more natural order comparators I provide them to the class under comparison as public constants.
Example:
public class ComparatorExample {
public static void main(String[] args) {
List<SomeObject> list = new ArrayList<>();
list.add(new SomeObject(1, "dhjf", "A"));
list.add(new SomeObject(4, "ghdg", "A"));
list.add(new SomeObject(6, "uztzt", "B"));
list.add(new SomeObject(1, "jhgf", "C"));
list.add(new SomeObject(3, "vbbn", "A"));
list.add(new SomeObject(99, "cvcxc", "A"));
list.add(new SomeObject(2, "dfdd", "G"));
// examples
Collections.sort(list, SomeObject.NATURAL);
Collections.sort(list, LexicographicOrderByCategoryAndName.INSTANCE);
LexicographicOrderByName.INSTANCE.compare(new SomeObject(99, "cvcxc", "A"), new SomeObject(54, "fdjnn", "C"));
}
public static class SomeObject {
public static Comparator<SomeObject> NATURAL = new Comparator<SomeObject>() {
@Override
public int compare(SomeObject arg0, SomeObject arg1) {
return arg1.getId() - arg0.getId();
}
};
private int id;
private String name;
private String category;
public SomeObject(int id, String name, String category) {
this.id = id;
this.name = name;
this.category = category;
}
public int getId() {
return id;
}
public String getName() {
return name;
}
public String getCategory() {
return category;
}
}
public static class LexicographicOrderByName implements Comparator<SomeObject> {
public static LexicographicOrderByName INSTANCE = new LexicographicOrderByName();
private LexicographicOrderByName() {
}
@Override
public int compare(SomeObject o1, SomeObject o2) {
return o1.getName().compareTo(o2.getName());
}
}
public static class LexicographicOrderByCategoryAndName implements Comparator<SomeObject> {
public static LexicographicOrderByCategoryAndName INSTANCE = new LexicographicOrderByCategoryAndName();
private LexicographicOrderByCategoryAndName() {
}
@Override
public int compare(SomeObject o1, SomeObject o2) {
int c = o1.getCategory().compareTo(o2.getCategory());
if (c == 0) {
c = o1.getName().compareTo(o2.getName());
}
return c;
}
}
}