DEV Community

loading...
Cover image for Comparable  vs Comparator in Java

Comparable vs Comparator in Java

Wagner Negrão 👨‍🔧
Hi, I created this blog to training my write in English and share that I'm learning in Java and other things. Always I'll be posting subjects in an objective way and short.
・4 min read

Hi guys, today I will write about a question that I was have been facing recently. I was writing a code and I needed to compare two things and I was in doubt about which comparator to use, then I was searching for comparators and find two the Comparable and the Comparator, reading about both I decided to write this post.

Now, I will contextualize a bit about Comparable. This is an interface that is implemented in the class that wants to create a comparison, this class that implements is obliged to implements a method called compareTo(), this method receives a value and compares it with something that is implemented inside the method.

To be able to explain this better I created the Product class, to be used, how to see below.

public class Product implements Comparable<Product>{
    private String name;
    private int quantity;
    private BigDecimal price;

    public Product(String name, int quantity, BigDecimal price) {
        this.name = name;
        this.quantity = quantity;
        this.price = price;
    }

  // Getters, Setters and toString

    @Override
    public int compareTo(Product product) {

        if (this.quantity > product.getQuantity()) return 1;

        return -1;
    }
}
Enter fullscreen mode Exit fullscreen mode

In that class was implemented the interface Comparable that receives a type of comparing, in our case, it is Product, in the class, we have three variables, like name, quantity, and price. Was created methods like constructors, getters, setters, and toString, but methods like getters, setters, and toString not were showed because it's not important to explain.

How we implement the interface, we have that creates a method compareTo() doing Override. This method is designated to create the logic of comparison for the class, in our case, we receive a Product and we do a comparison of quantity, pay attention, the return of the method is an integer, if the return is the first case of comparison then return 1 but if not then return -1, the implementation of method compareTo() understands this and return the correct comparison.

Now, with the Product class created we can start the Main class, in this class, we have the create the objects of Product, was added to a list, and for the order, we use the method Sort of the class Collections, this method receives an interface comparable like, the Product class implements comparable, we inherited from her, then we can pass the list that was created to method sort() the list by quantity.

public static void main(String[] args) {
        Product product1 = new Product("Laptop Dell", 12, new BigDecimal(600));
        Product product2 = new Product("Laptop Lenovo", 13, new BigDecimal(650));
        Product product3 = new Product("Laptop Macbook", 6, new BigDecimal(1200));

        List<Product> products = Arrays.asList(product1, product2, product3);

        Collections.sort(products);

        products.forEach(System.out::println);
    }
Enter fullscreen mode Exit fullscreen mode

With the Product class sorted by quantity.

Product{name='Laptop Macbook', quantity=6, price=1200}
Product{name='Laptop Dell', quantity=12, price=600}
Product{name='Laptop Lenovo', quantity=13, price=650}
Enter fullscreen mode Exit fullscreen mode

Now we go speak about the Comparator class, this class is an interface functional having only an abstract method, this allows us to instantiate the comparator class without the need to implement this interface. This is only possible after Java 8, which added the functional interfaces. That's why we are going to rebuild the Product class.

public class Product {
    private String name;
    private int quantity;
    private BigDecimal price;

    public Product(String name, int quantity, BigDecimal price) {
        this.name = name;
        this.quantity = quantity;
        this.price = price;
    }

  // Getters, Setters and toString
}
Enter fullscreen mode Exit fullscreen mode

With appropriate modifications made we can create an instance of the interface, this allows the creation of many ways to treat the data stream without the need to create methods or implements an interface. We are going to see some ways the create a comparable.

public static void main(String[] args) {
        Product product1 = new Product("Laptop Dell", 12, new BigDecimal(600));
        Product product2 = new Product("Laptop Lenovo", 13, new BigDecimal(650));
        Product product3 = new Product("Laptop Macbook", 6, new BigDecimal(1200));

        List<Product> products = Arrays.asList(product1, product2, product3);

        Comparator<Product> comparator = (p1, p2) -> {
            if (p1.getQuantity() > p2.getQuantity()) {
                return -1;
            } else {
                return 1;
            }
        };

        Collections.sort(products, comparator);

        products.forEach(System.out::println);
}
Enter fullscreen mode Exit fullscreen mode

In the example above, we can see that was instanced the Comparator class and created the comparison, where was compared the quantity of two values and return the biggest. With the comparator created, we can execute the Collection.sort(products, comparator), this comparison will go executed into the list in each value, so sorting the list per biggest quantity. Furthermore, we can create a method cleaner and use the method .comparing(), this is a static method the Comparator class has, this method implements code to comparation, and receive a unique value to be compared.

public static void main(String[] args) {

        List<Product> products = Arrays.asList(product1, product2, product3);

        products.sort(Comparator.comparing(p1 -> p1.getQuantity()));

        products.forEach(System.out::println);
    }
Enter fullscreen mode Exit fullscreen mode

Now, we will see the last example, this example will modify the Product class, we will create specific methods to sort the elements of the class, was created the quantityComparator, we instanced of way static the Comparator class and create the code to comparation as in the previous example.

public class Product {
    private String name;
    private int quantity;
    private BigDecimal price;

    public Product(String name, int quantity, BigDecimal price) {
        this.name = name;
        this.quantity = quantity;
        this.price = price;
    }

  // Getters, Setters and toString

    public static Comparator<Product> quantityComparator = new Comparator<Product>() {
        @Override
        public int compare(Product p1, Product p2) {
            if (p1.getQuantity() > p2.getQuantity()) {
                return 1;
            }
            return -1;
        }
    };
}
Enter fullscreen mode Exit fullscreen mode

In the Main class, we have the created the Collections.sort(products, Product.quantityComparator) and is called the method static quantityComparator, which presents way sort the list.

public static void main(String[] args) {

    List<Product> products = Arrays.asList(product1, product2, product3);

    Collections.sort(products, Product.quantityComparator);

    products.forEach(System.out::println);
}
Enter fullscreen mode Exit fullscreen mode

Both ways are very used but have that pay attention to some things when using these interfaces.The Comparable interface creates a sort pattern to class, them when use methods to sort will use the way that was created as in the example, but we have a problem, will have only one type of comparation. The Comparator interface can be instanced and create ways comparison in various ways, can be the principal class or in other class that needs some comparing.

Should be attention in some cases, Rules of business that are tied to that code and refactoring of code.

Discussion (0)