The comparator interface is implemented in a nested class
I am new to stackoverflow.com but I often used it to search for answers when I had a problem, but now I cannot find the result of my problem, so I ask here :) I am studying OCPJP SE 7 certification, exam 1Z0-804 and I'm using the book (there is only one available afaik, Ganesh \ Sharma) In the chapter on collections on the Comparator interface, the book provides this example of using the Comparator and Comparable interface to sort an array of Student elements, but the question about the comparator is:
import java.util.*;
class Student implements Comparable<Student> {
private String id, name;
private Double cgpa;
public String getName() {
return name;
}
public String getId() {
return id;
}
public Double getCgpa() {
return cgpa;
}
public Student(String studentId, String studentName, double studentCGPA) {
id=studentId;
name=studentName;
cgpa=studentCGPA;
}
public String toString() {
return id+" "+name+" "+cgpa;
}
public int compareTo(Student that) {
return this.id.compareTo(that.id);
}
}
class StudentCGPA implements Comparator<Student> {
public int compare(Student s1, Student s2) {
return s1.getCgpa().compareTo(s2.getCgpa());
}
}
class MyMainClass {
public static void main(String[] args) {
Student[] students = { new Student("cs011", "Lennon", 3.1),
new Student("cs021", "McCartney", 3.4),
new Student("cs012", "Harrison", 2.7),
new Student("cs022", "Starr", 3.7),
};
Arrays.sort(students, new StudentCGPA());
System.out.println(Arrays.toString(students));
}
}
So it creates a new class just to use the Comparator interface with two Student objects, but I think this is very awkward, so I'm wondering: why can't I use a nested class (inside Student)? Like this:
import java.util.*;
class Student implements Comparable<Student> {
private String id, name;
private Double cgpa;
public String getName() {
return name;
}
public String getId() {
return id;
}
public Double getCgpa() {
return cgpa;
}
public Student(String studentId, String studentName, double studentCGPA) {
id=studentId;
name=studentName;
cgpa=studentCGPA;
}
public String toString() {
return id+" "+name+" "+cgpa;
}
public int compareTo(Student that) {
return this.id.compareTo(that.id);
}
static class StudentCGPA implements Comparator<Student> {
public int compare(Student s1, Student s2) {
return s1.getCgpa().compareTo(s2.getCgpa());
}
}
}
class MyMainClass {
public static void main(String[] args) {
Student[] students = { new Student("cs011", "Lennon", 3.1),
new Student("cs021", "McCartney", 3.4),
new Student("cs012", "Harrison", 2.7),
new Student("cs022", "Starr", 3.7),
};
Arrays.sort(students, new Student.StudentCGPA());
System.out.println(Arrays.toString(students));
}
}
The book doesn't say anything about using nested classes instead of regular ones, but I can't figure out why it must be bad to do this ... Is there any problem with my code (second)? Should I follow what the book says because my Comparator implementation is wrong? (Note: the code compiles and runs without issue, with expected output in both cases)
[cs012 Harrison 2.7, cs011 Lennon 3.1, cs021 McCartney 3.4, cs022 Starr 3.7]
Please help: D Thanks in advance.
source to share
You can implement Comparator
as a static nested class of the object being compared , if , which you control that class (and if it is a class, not an interface). However, it is not unusual for you to want to compare instances of a class that you do not control according to an ordering that the target class does not natively support (whether by Comparable
or by providing the Comparator
class). In this case, you must create your own, separate one Comparator
.
Even when you are in control, the question of whether to implement Comparator
as top level classes is a question. I'm not sure why you call this "inconvenient"; I usually prefer to avoid nested classes when I can. Also note that if you're in the socket or not, the implementation class Comparator
will be compiled into a separate class file.
source to share
There is no real reason why you shouldn't actually implement both Comparable
and Comparator
.
class Student implements Comparable<Student>, Comparator<Student> {
private final String id;
private final String name;
private final Double cgpa;
public String getName() {
return name;
}
public String getId() {
return id;
}
public Double getCgpa() {
return cgpa;
}
public Student(String studentId, String studentName, double studentCGPA) {
id = studentId;
name = studentName;
cgpa = studentCGPA;
}
@Override
public String toString() {
return id + " " + name + " " + cgpa;
}
@Override
public int compareTo(Student that) {
return this.id.compareTo(that.id);
}
@Override
public int compare(Student o1, Student o2) {
return o1.getCgpa().compareTo(o2.getCgpa());
}
}
However, it is more advisable to implement only Comparable
and use other methods (like inner classes or anonymous classes) to select different orders.
class ByCgpa implements Comparator<Student> {
@Override
public int compare(Student o1, Student o2) {
return o1.getCgpa().compareTo(o2.getCgpa());
}
}
Collections.sort(list, new ByCgpa());
static void sortByCgpaAndName(Collection<Student> students) {
Collections.sort(students, new Comparator<Student> () {
@Override
public int compare(Student o1, Student o2) {
int byCgpa = o1.getCgpa().compareTo(o2.getCgpa());
return byCgpa != 0 ? byCgpa : o1.name.compareTo(o2.name);
}
});
}
See here for further discussion.
source to share