Arrays class in Java has a sort method which takes in an array and returns the sorted array. It works well for arrays of primitive types like int, char, float, double, etc., and even for String. But returns an error when we want to sort an array of objects.
Comparable
Consider the following example: Suppose we have a Player class which stores the player’s name, age, weight and number of his/her wins.
/** * Player --- store the players information */ class Player{ private String name; private int age; private int weight; private int wins; Player(String name, int age, int weight, int wins){ this.name = name; this.age = age; this.weight = weight; this.wins = wins; } //Getter method for name public String getName(){ return name; } //Setter method for name public void setName(String n){ name = n; } //Getter method for age public int getAge(){ return age; } //Setter method for age public void setAge(int a){ age = a; } //Getter method for weight public int getWeight(){ return weight; } //Setter method for weight public void setWeight(int w){ weight = w; } //Getter method for wins public int getWins(){ return wins; } //Setter method for wins public void setWins(int wi){ wins = wi; } public String toString(){ String msg = name + " " + age + " " + weight + " " + wins; return msg; } }
We want to sort an array of such players according to their names in ascending order. We can do this by using Arrays.sort(Object[] array) method.
public static void main(String[] args){ Player[] players = { new Player("John", 23, 45, 5), new Player("Andy", 20, 55, 7), new Player("Mani", 25, 47, 2), new Player("Bob", 19, 49, 9), new Player("Holly", 21, 50, 2) }; Arrays.sort(players); for(Player p: players) System.out.println(p.toString()); }
But we receive an error when we run the above code:
Exception in thread "main" java.lang.ClassCastException: Player cannot be cast to java.lang.Comparable at java.util.ComparableTimSort.countRunAndMakeAscending(ComparableTimSort.java:320) at java.util.ComparableTimSort.sort(ComparableTimSort.java:188) at java.util.Arrays.sort(Arrays.java:1246) at PlayerComparable.main(PlayerComparable.java:86)
This error occurred because we didn’t define the criteria according to which the objects must be sorted.
To sort objects, we have to compare them on the basis of their property. And to compare objects we need to make our object implement the Comparable interface and override its compare method.
Therefore, our class now implements the comparable interface and overrides the compare method which compares the name of the current object with the name of the passed object using the String’s compareTo method and returns the result accordingly.
class Player implements Comparable<Player>{ private String name; private int age; private int weight; private int wins; Player(String name, int age, int weight, int wins){ this.name = name; this.age = age; this.weight = weight; this.wins = wins; } //Getter method for name public String getName(){ return name; } //Setter method for name public void setName(String n){ name = n; } //Getter method for age public int getAge(){ return age; } //Setter method for age public void setAge(int a){ age = a; } //Getter method for weight public int getWeight(){ return weight; } //Setter method for weight public void setWeight(int w){ weight = w; } //Getter method for wins public int getWins(){ return wins; } //Setter method for wins public void setWins(int wi){ wins = wi; } @Override public int compareTo(Player p){ return name.compareTo(p.getName()); } public String toString(){ String msg = name + " " + age + " " + weight + " " + wins; return msg; } }
Now when we sort the array using Arrays.sort(players), the players are sorted in ascending order of their names:
Andy 20 55 7 Bob 19 49 9 Holly 21 50 2 John 23 45 5 Mani 25 47 2
Comparator
The comparable interface allows us to sort an object based on only one property. Another way to compare objects is to create a Comparator class using the Comparator interface. This method allows us to sort based on multiple properties of an object. So, using Comparator we can sort based on age, weight, and number of wins.
Suppose we want to sort the array on the basis of Player’s age. We can do that by creating a class AgeComparator which implements Comparator interface and overrides its compare method. In that method, we compare the ages of both objects and returns the result accordingly. Here I converted the primitive int values to Integer values and called the Integer’s compareTo method on them.
class AgeComparator implements Comparator<Player> { @Override public int compare(Player a, Player b){ return new Integer(a.getAge()).compareTo(new Integer(b.getAge())); } }
Player[] players = { new Player("John", 23, 45, 5), new Player("Andy", 20, 55, 7), new Player("John", 25, 47, 2), new Player("Bob", 19, 49, 9), new Player("Holly", 21, 50, 2) }; Arrays.sort(players, new AgeComparator()); for(Player p: players) System.out.println(p.toString());
Now we call Arrays.sort(array, comparator) method for the player’s array. This method now sorts the array based on ages of the players.
Bob 19 49 9 Andy 20 55 7 Holly 21 50 2 John 23 45 5 John 25 47 2
Similarly, we can write comparators to sort the array according to weight and wins. Example:
class WeightComparator implements Comparator<Player> { @Override public int compare(Player a, Player b){ return new Integer(a.getWeight()).compareTo(new Integer(b.getWeight())); } }
class WinsComparator implements Comparator<Player> { @Override public int compare(Player a, Player b){ return new Integer(a.getWins()).compareTo(new Integer(b.getWins())); } }
We can even sort on the basis of more than one property using the comparator. One example is to sort Players according to their names and wins. If names are same, we sort the objects in decreasing order of their wins. We can do this by first comparing the string names of two players. If names are same then only we compare the wins of two players and return the result accordingly.
class NameWinsComparator implements Comparator<Player>{ @Override public int compare(Player a, Player b){ String nameA = a.getName(); String nameB = b.getName(); if(nameA.equals(nameB)) return new Integer(b.getWins()).compareTo(new Integer(a.getWins())); else return nameA.compareTo(nameB); } }
The output for the player’s array is:
Andy 20 55 7 Bob 19 49 9 Holly 21 50 2 John 23 45 5 John 25 47 2
Here the last two elements have the same name John and they are sorted according to their wins in decreasing order.
Code for this post: PlayerComparable, PlayerComparator
Summary
Based on the above discussion the comparison between comparable and comparator can be summarized as below:
If you have any questions and suggestions, please write them in the comments below.
Thanks for stopping by. See you in the next post.