Student: ex15
Sorting with Comparators, and introduction to Lambda expressions
Part of a series of tutorial articles about a Student class.
Code examples referred to on this page can be found here: https://github.com/ucsb-cs156/student-tutorial/tree/ex15.
NOTE: NOT YET UPDATED FOR JAVA 17 and JUNIT 5 (TODO for W22, 01/05/22)
In ex14, we looked at implementing the java.lang.Comparable<T>
interface. This allows us to define what Java calls a natural order for a class.
If you have an ArrayList<Foo> myarray;
for any class Foo
that implements the java.lang.Comparable<Foo>
interface, you can sort that array can be sorted by simply invoking myarray.sort();
.
However, the limitation of the Comparable<T>
method is that you can only define one way to sort a particular class. For example, if we define sorting by perm, ascending, as the natural order for Student
, then myarray.sort()
will only every sort in this specific order.
In ex15, we’ll look at a more flexible way to define sort orders using something called a java.util.Comparator<T>
. This is a special object that, as the saying goes has one job. That job is to define a way of comparing two objects of type T
. Each Comparator
can be defined to sort by a different field; for example:
- One Comparator might sort by perm, ascending.
- Another Comparator might sort by name, in alphabetical order
- Another Comparator might sort (if we add
gpa
to the Student object) by GPA descending.
Consider also, a Course
object that might have attributes department
, and course number
and section number
. We might make a single comparator that sorts first by department, then by course number, and finally by section number.
In this exercise
- We’ll look at the
java.util.Comparator<T>
interface - We’ll discuss how it differs from
java.lang.Comparable<T>
- We’ll implement a
java.util.Comparator<Student>
to sort by name instead of by perm.
In our first attempt at a comparator, we’ll define it as a separate named class.
In practice, since Java 8, this is almost never done. Instead, comparators are usually defined at lambda expressions, which we’ll get to in ex17.
But, for this exercise, defining it as a separate named class will give us a good basis to understand how a comparator works, using methods that are familiar to us.
Looking Ahead
Our Student
class is kind of boring at the moment; it just has name
and perm
; and we’ve already built ways to sort on both of those.
To make it more interesting, so that we can look at more exotic ways of sorting, we’ll first do some updating to the Student
class itself.
In ex16, we’ll:
- split
name
intofirst
andlast
- add
units
as another field
Then in ex17
, we’ll look at three other ways to define comparators:
- As a named inner class
- As a “defined on the fly” instance of a class
- As a lambda expression
And finally, we’ll look at composite compartors, where we combine comparators using thenComparing
and reversed
.