Friday, November 29, 2013

Understanding Comparable and Comparator

In object oriented programming sometimes we need to compare the instances of the same class. Once the instances are comparable they cab be sorted. we are going to focus on designing a class and make its compare its instances by using "java.lang.Comparable" and "java.util.Comparator" interfaces.

Major difference between Comparable and Comparator is that former is used to define natural ordering of object e.g. lexicographic order for java.lang.String, while later is used to define any alternative ordering for an object.  Main usage of java.lang.Comparable and java.util.Comparator interface is for sorting list of objects in Java. For example to sort a list of Employee by there Id, we can use Comparable interface and to provide additional sorting capability, we can define multiple comparators e.g. AgeComparator to compare age of employee, SalaryComparator to compare salary of employees etc.  This brings another important difference between Comparator and Comparable interface in Java, you can have only one ordering via Comparable e.g. natural ordering, while you can define multiple Comparator

Comparable vs Comparator

1. Comparator interface is in java.util package, which implies it's a utility class, while Comparable interface is kept on java.lang package, which means it's essential for Java objects.

2. Based on syntax, one difference between Comparable and Comparator in Java is that former gives us compareTo(Object toCompare), which accepts an object, which now uses Generics from Java 1.5 onwards, while Comparator defines compare(Object obj1, Object obj2) method for comparing two object.

3. Continuing from previous difference between Comparator vs Comparable, former is used to compare current object, represented by this keyword, with another object, while Comparator compares two arbitrary object passed to compare() method in Java.

4. One of the key difference between Comparator and Comparable interface in Java is that, You can only have one compareTo() implementation for an object, while you can define multiple Comparator for comparing objects on different parameters e.g. for an Employee object, you can use compareTo() method to compare Employees on id,  known as natural ordering, while multiple compare() method to order employee on age, salary, name and city. It's also a best practice to declare Comparator as nested static classes in Java, because they are closely associated with objects they compare. 

5. Many Java classes, which make uses of Comparator and Comparable defaults to Comparable and provided overloaded method to work with arbitrary Comparator instance e.g. Collections.sort() method, which is used to sort Collection in Java has two implementation, one which sort object based on natural order i.e. by using java.lang.Comparable and other which accepts an implementation of java.util.Comparator interface.

6. One more key thing, which is not a difference but worth remembering is that both compareTo() and compare() method in Java must be consistent with equals() implementation i.e. if two methods are equal by equals() method than compareTo() and compare() must return zero. Failing to adhere this guideline, your object may break invariants of Java collection classes which rely on compare() or compareTo() e.g. TreeSet and TreeMap.

Example

package sachi.test.compare;

/*
 * Order class is a domain object which implements
 * Comparable interface to provide sorting on natural order.
 * Order also provides copule of custom Comparators to
 * sort object based uopn amount and customer
 */
import java.util.Comparator;

class Order implements Comparable<Order> {

    private int orderId;
    private int amount;
    private String customer;

    /*
     * Comparator implementation to Sort Order object based on Amount
     */
    public static class OrderByAmount implements Comparator<Order> {

        @Override
        public int compare(Order o1, Order o2) {
            return o1.amount > o2.amount ? 1 : (o1.amount < o2.amount ? -1 : 0);
        }
    }

    /*
     * Anohter implementation or Comparator interface to sort list of Order object
     * based upon customer name.
     */
    public static class OrderByCustomer implements Comparator<Order> {

        @Override
        public int compare(Order o1, Order o2) {
            return o1.customer.compareTo(o2.customer);
        }
    }

    public Order(int orderId, int amount, String customer) {
        this.orderId = orderId;
        this.amount = amount;
        this.customer = customer;
    }

  
    public int getAmount() {return amount; }
    public void setAmount(int amount) {this.amount = amount;}

    public String getCustomer() {return customer;}
    public void setCustomer(String customer) {this.customer = customer;}

    public int getOrderId() {return orderId;}
    public void setOrderId(int orderId) {this.orderId = orderId;}

    /*
     * Sorting on orderId is natural sorting for Order.
     */
    @Override
    public int compareTo(Order o) {
        return this.orderId > o.orderId ? 1 : (this.orderId < o.orderId ? -1 : 0);
    }
  
    /*
     * implementing toString method to print orderId of Order
     */
    @Override
    public String toString(){
        return String.valueOf(orderId);
    }

}



package sachi.test.compare;

import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;

/**
*
* Java program to test Object sorting in Java. This Java program
* test Comparable and Comparator implementation provided by Order
* class by sorting list of Order object in ascending and descending order.
* Both in natural order using Comparable and custom Order using Comparator in Java
*/
public class ObjectSortingExample {
public static void main(String args[]) {
     
        //Creating Order object to demonstrate Sorting of Object in Java
        Order ord1 = new Order(101,2000, "Sony");
        Order ord2 = new Order(102,4000, "Hitachi");
        Order ord3 = new Order(103,6000, "Philips");
      
        //putting Objects into Collection to sort
        List<Order> orders = new ArrayList<Order>();
        orders.add(ord3);
        orders.add(ord1);
        orders.add(ord2);
      
        //printing unsorted collection
        System.out.println("Unsorted Collection : " + orders);
      
        //Sorting Order Object on natural order - ascending
        Collections.sort(orders);
      
        //printing sorted collection
        System.out.println("List of Order object sorted in natural order : " + orders);
      
        // Sorting object in descending order in Java
        Collections.sort(orders, Collections.reverseOrder());
        System.out.println("List of object sorted in descending order : " + orders);
              
        //Sorting object using Comparator in Java
        Collections.sort(orders, new Order.OrderByAmount());
        System.out.println("List of Order object sorted using Comparator - amount : " + orders);
      
        // Comparator sorting Example - Sorting based on customer
        Collections.sort(orders, new Order.OrderByCustomer());
        System.out.println("Collection of Orders sorted using Comparator - by customer : " + orders);
    }

}

Output:

Unsorted Collection : [103, 101, 102]
List of Order object sorted in natural order : [101, 102, 103]
List of object sorted in descending order : [103, 102, 101]
List of Order object sorted using Comparator - amount : [101, 102, 103]

Collection of Orders sorted using Comparator - by customer : [102, 103, 101]




No comments:

Post a Comment