Making Student Comparable

Comparable is the contract. Now let’s have Student implement it. We declare that the class implements Comparable<Student> and provide the one method the contract requires:

public class Student implements Comparable<Student> {
  // ...fields, constructor, equals, hashCode...

  @Override
  public int compareTo(Student other) {
    return Integer.compare(this.id, other.id);
  }
}

Integer.compare compares the two IDs and returns the negative, zero, or positive value for us. So a student with a smaller ID comes before one with a larger ID.

Keep it consistent with equals

We ordered by id, the same field we used for equals.

Think about what each method says when two students share an ID. equals reports that they are the same student. compareTo returns 0, which reports that they are equal in order. The two agree. Now suppose we had ordered by GPA instead. Two different students with the same GPA would make compareTo return 0. Any code that sorts or searches by order would treat those two students as interchangeable, but equals says they are different people. As we will see later in binary search, code that sorts a list and then searches it can fail to find a student who is in the list, because the search stopped at the other student with the same GPA.

The rule of thumb: compareTo should return 0 exactly when equals returns true. We keyed both on id, so we get that.

Natural ordering

We chose id. We could have ordered students by name, or by GPA, or by anything else. compareTo defines the type’s natural ordering. That is the order built into the type. It is the order you get when you do not ask for a different one.

A type gets exactly one natural ordering, because it has exactly one compareTo. So a Student is ordered by ID and nothing else, unless we go back and edit the class.

Now that Student is comparable, we have what we need to sort a roster. In the next section we make selectionSort itself generic, so it can sort any type that implements Comparable.