[Java] Comparable vs Comparator

java comparable vs comparator

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:

java comparable vs comparator
Table 1: Comparable vs Comparator

If you have any questions and suggestions, please write them in the comments below.

Thanks for stopping by. See you in the next post.

 

 


4 responses to “[Java] Comparable vs Comparator”

  1. import java.util.*;
    public class ChatBox{

    public static class Chat implements Comparable{
    int Chat_id;
    int User_id;
    int Message_Size;
    String Message;

    public Chat(int t_id, int user_id, int message_size, String message){
    this.Chat_id = t_id;
    this.User_id = user_id;
    this.Message_Size = message_size;
    this.Message = message;
    }

    @Override
    public int compareTo(Chat t){
    int t_id = ((Chat)t).Chat_id;
    return this.Chat_id – t_id;
    }

    /*Comparator for sorting by user_id*/
    public static Comparator chatComparatorByUserId = new Comparator(){
    public int compare(Chat c1, Chat c2){
    return c1.User_id – c2.User_id;
    }
    };

    /*Comparator for sorting by Message Size*/
    public static Comparator chatComparatorByMessageSize = new Comparator(){
    public int compare(Chat c1, Chat c2){
    return c1.Message_Size – c2.Message_Size;
    }
    };

    @Override
    public String toString(){
    return “[ Chat_id = “+this.Chat_id+” User_id = “+this.User_id+” Message = “+this.Message+” Message_size = “+this.Message_Size+” ]”;
    }
    }

    /*Another way to define comparator as a class*/
    public static class ChatComparatorByMessage implements Comparator{
    public int compare(Chat c1, Chat c2){
    return c1.Message.compareTo(c2.Message);
    }
    }

    public static void main(String [] a){
    List chats = new ArrayList();
    chats.add(new Chat(2,3,10,”this is 2″));
    chats.add(new Chat(1,1,9,”this is 1″));
    chats.add(new Chat(4,5,19,”this is 4″));
    chats.add(new Chat(3,10,50,”this is 3″));
    chats.add(new Chat(6,8,20,”this is 6″));
    chats.add(new Chat(5,2,11,”this is 5″));

    Collections.sort(chats);
    /*Sorted by Transaction_Id*/
    System.out.println(“Sorted by Transaction_Id”);
    for(Chat t : chats)
    System.out.println(t);

    /*Sorted by user_Id*/
    Collections.sort(chats, Chat.chatComparatorByUserId);
    System.out.println(“Sorted by User_Id”);
    for(Chat t : chats)
    System.out.println(t);

    /*Sorted by Message_Size*/
    Collections.sort(chats, Chat.chatComparatorByMessageSize);
    System.out.println(“Sorted by Message_Size”);
    for(Chat t : chats)
    System.out.println(t);

    /*Sorted by Message*/
    Collections.sort(chats, new ChatComparatorByMessage());
    System.out.println(“Sorted by Message”);
    for(Chat t : chats)
    System.out.println(t);
    }
    }