The comparator interface (practical application) #practicalJava
Table of contents
Problem statement
Here I will start with a real world problem. Given a list of songs with the following details for each songs
Song title
Number of streams on Spotify
Year of release
You are expected to store the data in such a way that the user of the list can sort the songs by either title, streams or year.
Recall that the Comparable
interface only provides a way to sort data based on one of its property and as such can not be used here. For this reason, we will be using the Comparator
interface. You can check the link below to understand what problem the comparable
interface solves.
https://unyimeudohdsa.hashnode.dev/the-comparable-interface-in-java-practical-application
Introduction
The Comparator
interface is employed to facilitate the sorting of a list of objects based on various criteria. These criteria refer to different properties of the object. Just like the Comparable
interface that provides the compareTo
method which does the actual comparison, the Comparator
interface provides only one method called the compare
method which does the actual comparison.
Note: Unlike the compareTo
method that is implemented inside the object to be compared, the compare
method is implemented outside the object to be compared. Implementing the method that does the actual comparison inside the object creates a limitation that only one property of the object can be used as a criterion since we cannot override the same method two times in an object.
But implementing the method that does the actual comparison outside the object enables you to use different properties of the object as the criterion. Since a method cannot exist on it own outside a class in java, it therefore means that you will be creating a class for each property that you want to compare and in the class you will have your compare
method.
Implementation
⇒ First of all, you define the object with all its properties.
class Song {
String songTitle;
int numberOfStreams;
LocalDate yearOfRelease;
public Song(String songTitle, int numberOfStreams, LocalDate yearOfRelease){
this.songTitle = songTitle;
this.numberOfStreams = numberOfStreams;
this.yearOfRelease = yearOfRelease;
}
public String getSongDetail(){
return "Song title: " + songTitle + ", Year: " + yearOfRelease + ", Streams: " + numberOfStreams;
}
}
⇒ Then define the class for each property of your object class (Song) that you want to use as a criterion. It should be noted here that the compare
method in Comparator
interface here returns the same thing as the compareTo
method in Comparable
interface. That is
If both items compared are the same we return 0
If the first argument is greater we return 1
If the second argument is smaller we return -1
class StreamsComparator implements Comparator<Song>{
@Override
public int compare (Song song1, Song song2){
if(song1.numberOfStreams == song2.numberOfStreams){
return 0;
}
if(song1.numberOfStreams > song2.numberOfStreams){
return 1;
}
return -1;
}
}
class SongTitleComparator implements Comparator<Song>{
@Override
public int compare (Song song1, Song song2){
if (song1.songTitle == null && song2.songTitle == null) {
return 0;
} else if (song1.songTitle.compareTo(song2.songTitle) == 1) {
return 1;
}
return -1;
}
}
class DateComparator implements Comparator<Song> {
@Override
public int compare(Song song1, Song song2) {
if (song1.yearOfRelease == null && song2.yearOfRelease == null) {
return 0;
} else if (song1.yearOfRelease == null) {
return -1;
} else if (song2.yearOfRelease == null) {
return 1;
} else {
return song1.yearOfRelease.compareTo(song2.yearOfRelease);
}
}
}
⇒ Then we choose a data structure that is iterable and insert instances of our objects in it.
ArrayList<Song> playList = new ArrayList<Song>();
playList.add(new Song("Dumebi", 8000, LocalDate.of(2022, 7, 16)));
playList.add(new Song("Bad commando", 10000, LocalDate.of(2024, 3, 20)));
playList.add(new Song("Calm down", 90000, LocalDate.of(2023, 12, 12)));
⇒ To sort the list based on a particular property, you pass in the list and the corresponding comparator class into the sort method of the Collection class.
Collections.sort(playList, new StreamsComparator()); // sort by number of streams
Collections.sort(playList, new SongTitleComparator()); // sort by title
Collections.sort(playList, new DateComparator());// sort by date released
⇒ You can then loop through the list and see what how they are sorted
8000
10000
90000
Bad commando
Calm down
Dumebi
2022-07-16
2023-12-12
2024-03-20
Full code
package MergeSort;
import java.awt.*;
import java.time.LocalDate;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.Comparato
public class UseComparable {
public static void main(String[] args){
ArrayList<Song> playList = new ArrayList<Song>();
playList.add(new Song("Dumebi", 8000, LocalDate.of(2022, 7, 16)));
playList.add(new Song("Bad commando", 10000, LocalDate.of(2024, 3, 20)));
playList.add(new Song("Calm down", 90000, LocalDate.of(2023, 12, 12)));
// Collections.sort(playList, new StreamsComparator());
// Collections.sort(playList, new SongTitleComparator());
Collections.sort(playList, new DateComparator());
for(Song song: playList){
System.out.println(song.yearOfRelease);
}
// Arrays.sort(playList, new StreamsComparator());
}
}
class Song {
String songTitle;
int numberOfStreams;
LocalDate yearOfRelease;
public Song(String songTitle, int numberOfStreams, LocalDate yearOfRelease){
this.songTitle = songTitle;
this.numberOfStreams = numberOfStreams;
this.yearOfRelease = yearOfRelease;
}
public String getSongDetail(){
return "Song title: " + songTitle + ", Year: " + yearOfRelease + ", Streams: " + numberOfStreams;
}
}
class StreamsComparator implements Comparator<Song>{
@Override
public int compare (Song song1, Song song2){
if(song1.numberOfStreams == song2.numberOfStreams){
return 0;
}
if(song1.numberOfStreams > song2.numberOfStreams){
return 1;
}
return -1;
}
}
class SongTitleComparator implements Comparator<Song>{
@Override
public int compare (Song song1, Song song2){
if (song1.songTitle == null && song2.songTitle == null) {
return 0;
} else if (song1.songTitle.compareTo(song2.songTitle) == 1) {
return 1;
}
return -1;
}
}
class DateComparator implements Comparator<Song> {
@Override
public int compare(Song song1, Song song2) {
if (song1.yearOfRelease == null && song2.yearOfRelease == null) {
return 0;
} else if (song1.yearOfRelease == null) {
return -1;
} else if (song2.yearOfRelease == null) {
return 1;
} else {
return song1.yearOfRelease.compareTo(song2.yearOfRelease);
}
}
}
This marks the end of the article and I will like to know in the comment section how many people recognized the artist I used as example.
Thank you very much for your time and if the article was useful do give it a like, post and social media with the hashtag and share with your friends. If there is any recommendation or correction, you do that in the comment section.