Reputation: 1099
Extreme newbie here struggling to get a handle on all the different ways a list may be sorted. Suppose I have a list of objects and each object has several keys that might be used for sorting in different circumstances. I got some very useful information from this thread: Java Interface Comparator static compare, using Qwerky’s first example as a model created:
class Dog {
private String name;
private int age;
private int height;
private int weight;
Dog(String n, int a, int b, int c){
name = n;
age = a;
height = b;
weight = c;
}
public String getDogName(){
return name;
}
public int getDogAge(){
return age;
}
public int getDogHeight(){
return height;
}
public int getDogWeight(){
return weight;
}
}
class DogComparator1 implements Comparator<Dog> {
@Override
public int compare(Dog d, Dog d1){
return d.getDogAge() - d1.getDogAge();
}
}
class DogComparator2 implements Comparator<Dog> {
@Override
public int compare(Dog d, Dog d1){
return d.getDogHeight() - d1.getDogHeight();
}
}
class DogComparator3 implements Comparator<Dog> {
@Override
public int compare(Dog d, Dog d1){
return d.getDogWeight() - d1.getDogWeight();
}
}
public class Example{
public static void main(String args[]){
// Creat list of dog objects
List<Dog> dogList = new ArrayList<>();
// Add a buch of dogs to the list here
.
.
// Create the Comparators
DogComparator1 compare1 = new DogComparator1();
DogComparator2 compare2 = new DogComparator2();
DogComparator3 compare3 = new DogComparator3();
// Sort the list using Comparators
Collections.sort(list, compare1); // Sort by age
Collections.sort(list, compare2); // Sort by height
Collections.sort(list, compare3); // Sort by weight
}
}
But, this just doesn’t seem right. I think I want to pull the comparator definitions “inside” the Dog class to nicely encapsulate them. But, can’t figure out how to do it.
Am I on the right track? If so, help with the proper syntax would be greatly appreciated.
Upvotes: 4
Views: 430
Reputation: 15497
Consider using Comparator#comparingInt
to create your comparators:
list.sort(Comparator.comparingInt(Dog::getDogAge)); // Sort by age
list.sort(Comparator.comparingInt(Dog::getDogHeight)); // Sort by height
list.sort(Comparator.comparingInt(Dog::getDogWeight)); // Sort by weight
This way saves you from having to write your own Comparator<Dog>
implementations as you are doing now and it's easy to see exactly what is being compared.
Since the Comparator
s are already only using the public methods of Dog
and they are this short there is not much reason to encapsulate them inside of Dog
.
Upvotes: 1
Reputation: 4051
I do not think it is a responsibility of the Dog class to know the different ways in which you can compare it. You can, however create those comparators as inner classes if that would feel more "encapsulated" for you (and even make this class private).
I.e. you could, inside Dog class, do this:
public class Dog {
(...)
public Comparator<Dog> getAgeComparator() {
return new AgeComparator();
}
private static class AgeComparator implements Comparator<Dog> {
@Override
public int compare(Dog d, Dog d1){
return d.getDogAge() - d1.getDogAge();
}
}
Or, instead of creating a getAgeComparator()
method expose those comparators as:
public static final Comparator<Dog> AGE_COMPARATOR = new AgeComparator();
You could also just create the anonymous implementation there. The way you are doing this though is correct. I would not make Dog aware of how it can be compared. You could easily have those implementations live elsewhere, or even create anonymous class implementations on the fly if you do not reuse them. What you are trying to achieve is a wrong understanding of encapsulation.
You can create a default comparator though by making Dog
class implement Comparable<Dog>
:
public class Dog implements Comparable<Dog> {
public int compareTo(Dog dog) {
return AGE_COMPARATOR.compare(this, dog); // or inline comparison here
}
(...)
}
Upvotes: 3
Reputation: 40378
You are definitely on the right track.
I would just add this inside your Dog
class:
public static final Comparator<Dog> COMPARE_BY_AGE = new Comparator<Dog>() {
@Override
public int compare(Dog d, Dog d1) {
return d.getDogAge() - d1.getDogAge();
}
};
public static final Comparator<Dog> COMPARE_BY_HEIGHT = new Comparator<Dog>() {
@Override
public int compare(Dog d, Dog d1) {
return d.getDogHeight() - d1.getDogHeight();
}
};
public static final Comparator<Dog> COMPARE_BY_WEIGHT = new Comparator<Dog>() {
@Override
public int compare(Dog d, Dog d1) {
return d.getDogWeight() - d1.getDogWeight();
}
};
And then the usage is like follows:
// Sort the list using Comparators
Collections.sort(list, Dog.COMPARE_BY_AGE); // Sort by age
Collections.sort(list, Dog.COMPARE_BY_HEIGHT); // Sort by height
Collections.sort(list, Dog.COMPARE_BY_WEIGHT); // Sort by weight
Upvotes: 5