The comparator interface (practical application) #practicalJava

Problem statement

Here I will start with a real world problem. Given a list of songs with the following details for each songs

  1. Song title

  2. Number of streams on Spotify

  3. 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 Comparatorinterface 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.