Monday, April 24, 2023

How to use Comparable Interface in Java? compareTo() Example

Hello, guys, today I am going to talk about one of the fundamental concepts in Java, defining the natural ordering of the objects like lexicographical order for String and numerical order for Number classes like Integer, Double, Float, etc. The compareTo() method is defined in the java.lang.Comparable interface. It is used to define the natural ordering of an object, for example String class override compareTo() to define the lexicographical order for String objects. Integer class override compareTo() to define the numeric ordering of integer objects.

Similarly, you can override the compareTo() method by implementing a Comparable interface to define the natural order in which you want to order your object. For example, an Order should be ordered by order id hence compareTo() must provide logic for that.

Now, the question comes where does this natural ordering is required? Why do you need it in the first place? Well, in a real-world application, you are not dealing with just one object, you deal with a collection of objects.

For example, in an e-commerce system, you have millions of orders and if you want to display them, you cannot display them in any random order, which won't do any benefit. You need to print or display them in an order which makes sense. The most common order is known as the natural order e.g. list of orders ordered by their OrderId.

The compareTo() method is mainly used in the sorting process. In Java programs, when you often sort a list of objects by calling Collections.sort(list), they are sorted based upon their natural order which is defined by compareTo() method.

You should also remember that compareTo() returns a positive number if the current object is greater than the given object, a negative number if the current (this) object is less than the given object, and zero if both objects are equal.

One of the subtle detail about compareTo() is that it must match with equals() method like if objects are equal with equals() then their compareTo() must return zero, failing to oblige this rule can create problems if you store your objects which use both equals() and compareTo() method e.g. TreeSet and TreeMap.

And, If you are new to the Java world then I also recommend you go through The Complete Java MasterClass on Udemy to learn Java in a better and more structured way. This is one of the best and up-to-date courses to learn Java online.





Java compareTo() Example

There are a lot of classes in Java that implements the compareTo() method e.g. String, Integer, Long, Float, Double, etc. You can see their implementation and how they work by running these examples. For example, let's say, you have a list of String and you want to sort them in increasing order. You don't need to do anything, this ordering is defined in the compareTo() method of java.lang.String class as shown below:

public int compareTo(String anotherString) {
    int len1 = value.length;
    int len2 = anotherString.value.length;
    int lim = Math.min(len1, len2);
    char v1[] = value;
    char v2[] = anotherString.value;

    int k = 0;
    while (k < lim) {
      char c1 = v1[k];
      char c2 = v2[k];
      if (c1 != c2) {
        return c1 - c2;
      }
      k++;
    }
    return len1 - len2;
  }

This method compares two strings lexicographically. The comparison is based on the Unicode value of each character in the strings. The character sequence represented by this String object is compared lexicographically to the character sequence represented by the argument string.

In lexicographic ordering, If two strings are different, then either they have different characters at some index that is a valid index for both strings, or their lengths are different or both.

All you need to do is just call the Collections.sort() method to sort the list of String. This method uses the Strategy design patterns and calls compareTo() method which defines the sorting strategy of the object. Every object is free to override how they compare, which we will see in the next section. Btw, here is a diagram that shows that both String and wrapper classes implement Comparable interfaces in Java:

Java Comparable Interface and compareTo() Example



Java Comparable and compareTo() Example

Now, let's how to override the compareTo() method for a user object. In this program, we'll create a user-defined object called order which has fields like OrderId (a non-negative number), Customer details, and total amount. The natural order for this object is by OrderId e.g. on increasing order, OrderId with 1 will come before OrderId 2 and on decreasing order, Order with Id 2 will come before an object with Id 1.

import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;

/*
 * Java Program to show compareTo() example
 * and Comparable example
 */

public class Main {

  public static void main(String[] args) {

    // let's create couple of order to compare
    Order first = new Order(1, "abc", BigDecimal.TEN);
    Order second = new Order(2, "xyz", new BigDecimal("10"));
    Order third = new Order(3, "kbc", BigDecimal.ONE);

    // let's compare first and second order
    int result = first.compareTo(second);
    if (result > 0) {
      System.out.println("first order is greater than second");
      
    } else if (result < 0) {
      System.out.println("first order is less than second");
      
    } else if (result == 0) {
      System.out.println("both orders are same");
    }

    // let sort the order as per natural order defined by compareTo()
    List<Order> listOfOrders = new ArrayList<>();
    listOfOrders.add(first);
    listOfOrders.add(third);
    listOfOrders.add(second);

    Collections.sort(listOfOrders);
    System.out.println(listOfOrders);

  }

}

/*
 * A class which implements Comparable interface and overrides compareTo()
 * method. Make sure you use Generic and define type parameter for Comparable,
 * in this way, you don't need to cast Object to Order inside compareTo() method
 */
class Order implements Comparable<Order> {
  private int id;
  private String customer;
  private BigDecimal total;

  public Order(int id, String customer, BigDecimal total) {
    this.id = id;
    this.customer = customer;
    this.total = total;
  }

  @Override
  public int compareTo(Order ord) {
    return this.id - ord.id;
  }

  @Override
  public String toString() {
    return "OrderId-" + id;
  }

}

Output
the first order is less than second
[OrderId-1, OrderId-2, OrderId-3]

You can see from the output that the first order is less than the second because the id of the first order is 1 and the id of the second order is 2. So, when you sort them in increasing order, the first order will come before the second order, which is also evident from the second line of output.

Anyway, It's not that you are only limited to one order, you can, of course, define custom ordering. ordering order by the customer, by date, or even by the total amount, but Comparable is not for that. You need to use the Comparator interface and overrides its compare() method to define customized ordering similar to order by clause of SQL. You can learn more about the difference between Comparator and Comparable here.


That's all in this Java Comparable and compareTo() example. Along with equals(), hashcode(), and compare() methods, compareTo() is also one of the fundamentals every Java programmer should know. It's very important to define the ordering for data objects because you don't want them sorted in any random order, so make sure when you create an object you provide an implementation for critical methods like equals, hashcode, compare, toString, and compareTo.



Other Java basic tutorials you may like
  • How to override the equals() method in Java? (example)
  • 6 Advanced Comparator Examples in Java (Example)
  • How to override the hashcode() method in Java? (example)
  • How to override compare() method in Java? (example)
  • How to override the toString() method in Java? (example)
  • How to implement the clone() method in Java? (example)
  • How to override clone() with a mutable field in Java? (example)
  • What is the difference between Comparable and Comparator in Java? (answer)
  • How to compare objects by multiple fields in Java? (comparator example)
  • How to use comparing() and thenComparing() in Java? (comparing example)


No comments:

Post a Comment