Wednesday, July 14, 2021

How to Order and Sort Objects in Java? Comparator and Comparable Example

Java Object Sorting Example
How do you sort a list of Objects in Java is one of the frequently asked coding questions in Java interviews and surprisingly not every Java programmers know How sorting of object happens in Java. Comparator and Comparable interface along with Collections.sort() method are used to sort the list of objects in Java. compare() and compareTo() method of Comparator and Comparable interface provides comparison logic needed for sorting objects. compareTo() method is used to provide Object's natural order sorting and compare() method is used to sort Object with any arbitrary field. 

Almost all value classes in the Java library e.g. String, Integer, Double, BigDecimal implement compareTo() to specify their natural sorting order.

While overriding the compareTo method String is sorted lexicographically and Integers are sorted numerically. Just beware that it must inconsistent with the equals method i.e. two objects which are equal by equals method in Java, compareTo() method must return zero for them.  

Anyway,  sorting standard value Objects is not a problem for many Java programmers but some of them really struggle when it comes to sorting custom Objects or domain Objects. In this Java sorting tutorial, we will create a custom object and sort a list of Objects in ascending and descending order.



Sorting list of Object in ascending and descending Order

Here is the list of steps we will follow in this Java sorting tutorial for creating custom Object, implementing Comparable or Comparator, and finally sorting the list of Object in ascending and descending order. Our knowledge of sorting ArrayList in ascending and descending order will come in handy here.

1) Create Order object as custom or domain object
2) Implement Comparable and Comparator interface to define sorting logic
3) Sort list of Object using Collections.sort method

By the way, after Java 8, using Comparator and Comparable has been even easier. You can lambda expression and method reference to create more clear and concise code for Comparator. It improves both readability and reusability. You can see these Java 8 courses to learn more about those features. 

How to Order and Sort Objects in Java? Comparator and Comparable Example


And, here is our complete Java program to demonstrate how to use Comparato rand Comparator to define the order for objects and how to sort them in both natural and custom order. 


package
test;

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 objects in ascending and descending order.
 * Both in natural order using Comparable and custom Order using Comparator in Java
 *
 * @author http://java67.blogspot.com
 */

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);
    }
}

/*
 * Order class is a domain object which implements
 * Comparable interface to provide sorting on the natural order.
 * Order also provides a couple of custom Comparators to
 * sort object based upon amount and customer
 */

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);
        }
    }

    /*
     * Another implementation or Comparator interface
     * to sort the list of the 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);
    }
}

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]


Important points about Comparator and Comparable


1. If you implement Comparable interface and override compareTo() method it must be consistent with equals() method i.e. for an equal object by equals() method compareTo() must return zero. failing to so will affect the contract of SortedSet e.g. TreeSet and SortedMap like TreeMap, which uses the compareTo() method for checking equality

2. Some programmers use Integer subtraction to implement compareTo() in Java, which can cause overflow issues if both integers are not positive. See How compareTo works in Java for more details.

3. This example of sorting Objects in Java also shows a good example of Where to use nested static classes in Java. In this example, We have created a custom Comparator as a static inner class So that they can access properties of Order for comparison, and also they are only used in the context of Order class.

4. Don't forget to revise the Difference between Comparator and Comparable in Java, which is one of the most asked Java questions on Interviews.

5. Remember to use Collections.reverseOrder() comparator for sorting Objects in reverse order or descending order, as shown in this example.

6. Use Generics while implementing Comparator and Comparable interface, which prevents the error of accidentally overloading compareTo() and compare() method instead of overriding it because both of these methods accept Object as a parameter. By using Generics and @Override annotation we effectively remove that subtle error.

7. This Object Sorting Example in Java also teaches us Why you should override toString() in Java. If you are going to store your Object in Collection like List, Set or Map then printing Collection will call toString() method of each stored Object. By providing readable String format you can see What is stored in a collection in logs. This is also a useful logging tip in Java.

That's all on How to sort the list of Objects in Java. It's up to you whether to use the Comparable or Comparator interface for implementing sorting logic in Java.

Other Java Interview Questions you may find good

25 comments:

  1. Great example,thanks a lot

    ReplyDelete
  2. I am not able to understand if nested static class is used inside Order class,then why the static class is referenced through the outer class as Order.OrderbyAmount.
    As per my understanding,nested static class can be referenced through itself.

    ReplyDelete
    Replies
    1. Nested static class is like static member of the outer class , so it will be accessed like other static members of the class

      Delete
  3. This was great, I learnt a lot from it. Thanks for sharing knowledge!

    ReplyDelete
  4. your code is wrong...

    try with this and pls find the answer why is this happening..in case of amount

    Order ord1 = new Order(101,600000000, "Sony");
    Order ord2 = new Order(102,4000, "Hitachi");
    Order ord3 = new Order(103,2000, "Philips");
    it should print
    List of Order object sorted using Comparator - amount : [101, 102, 103]
    but i am geting..

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

    so please tell me how we get the required result.

    ReplyDelete
    Replies
    1. hi prakash ,

      above example is works fine ,may be in your code something wrong checkout condition which you apply.

      thanks
      chirag@india

      Delete
  5. Hi Chirag,

    NO,if i change the amount as

    Order ord1 = new Order(101,600000000, "Sony");
    Order ord2 = new Order(102,4000, "Hitachi");
    Order ord3 = new Order(103,2000, "Philips");

    then it wont give correct output.

    ReplyDelete
  6. How to get reverse order for the below

    Collections.sort(orders, new Order.OrderByAmount());

    ReplyDelete
  7. How to sort Hashmap based on values?

    ReplyDelete
  8. Simple example.....thanx

    ReplyDelete
  9. or like this in java8 :
    LIST.stream().sorted(Comparator.comparing(CLASS::ATTRIBUTE));

    ReplyDelete
  10. ArrayList Object objt = new ArrayList Object();

    objt.add(4);
    objt.add(5);
    objt.add(6);
    objt.add(1);

    Collections.sort(objt);

    can we sort this arraylist?

    ReplyDelete
  11. Nice example. Thanks

    ReplyDelete
  12. HI,

    How can we do this long data type?
    Means in my Java object I have long data type based on that I need to do sorting, for example that long type is time stamp..

    ReplyDelete
  13. public static String findFizzBuzz(int data){

    return (data % 3==0 && data % 5==0) ?"FizzBuzz":(data%5==0?"Buzz":(data%3==0?"Fizz":String.valueOf(data)));

    }

    ReplyDelete
  14. i want to display total record in sorting....
    please can any one help for me

    ReplyDelete
  15. The 7th point is not happening.. That is when ever we adding object in list, Object toString() is not getting called.
    Can you elaborate it ?

    ReplyDelete
    Replies
    1. Hello N.V, I don't get you, are you saying when you print collection, toString() method of individual object doesn't get called?

      Delete
  16. How can I implement this

    Public interface Sort{
    public void Sort(int[] numbers, int option);
    }

    ReplyDelete
    Replies
    1. you just need to implement Sort function, like

      QuickSort implmeents Sort{

      public void Sort(int[] numbers, int option){
      // logic for quicksort
      }
      }

      Delete
  17. How to sort using Comparable if my datatype is double?

    ReplyDelete
    Replies
    1. You can use Double wrapper class and its Double.compareTo() method to compare double values.

      Delete
  18. How we can separate incomparable elements of a collection

    ReplyDelete
  19. How we can separate incomparable elements of a collection

    ReplyDelete

Feel free to comment, ask questions if you have any doubt.