Loading [MathJax]/jax/output/HTML-CSS/config.js

riven

Riven

Riven

comparator in java with example

In Java, sorting collections of objects is a common task that often requires custom sorting criteria. The Comparator interface plays a crucial role in this process, allowing developers to define their own order for sorting objects. 

What is a Comparators?

The Comparator interface is part of the java.util package and is used to compare two objects for order. It provides a means to define custom sorting logic that can be used with various collection classes such as lists, sets, and maps. Unlike the Comparable interface, which requires the class to implement a natural ordering, Comparator allows you to create multiple ways to compare objects of the same class.

Key Characteristics of Comparators

  1. Flexible Sorting: Allows multiple sorting strategies for the same class.
  2. Separation of Logic: Keeps the sorting logic separate from the object’s class definition.
  3. Functional Interface: Since Java 8, Comparator is a functional interface, meaning it can be used with lambda expressions.

The Comparators Interface

The Comparator interface includes several methods, but the most important ones are:

  • int compare(T o1, T o2): Compares its two arguments for order. Returns a negative integer, zero, or a positive integer if the first argument is less than, equal to, or greater than the second.
  • boolean equals(Object obj): Indicates whether some other object is “equal to” this comparator.

Example of a Simple Comparators

Let’s create a simple example to illustrate the use of a Comparators to sort a list of integers in reverse order.

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

public class ComparatorExample {
    public static void main(String[] args) {
        List<Integer> numbers = new ArrayList<>();
        numbers.add(1);
        numbers.add(4);
        numbers.add(3);
        numbers.add(2);
        numbers.add(5);

        // Create a comparator for reverse order
        Comparator<Integer> reverseComparator = (o1, o2) -> o2 - o1;

        // Sort using the comparator
        Collections.sort(numbers, reverseComparator);

        // Display the sorted list
        System.out.println("Sorted in reverse order: " + numbers);
    }
}
//Output:

Sorted in reverse order: [5, 4, 3, 2, 1]

In this example, we create a Comparator that sorts integers in reverse order and use it to sort a list.

Implementing Custom Comparators

You can implement custom comparators by creating a class that implements the Comparator interface. This allows you to define multiple comparison strategies for the same object type.

Example: Custom Comparators for Employee Objects

Let’s define a Employee class and create a comparator to sort employees by their names and another to sort them by their ages.

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

class Employee {
    private String name;
    private int age;

    public Employee(String name, int age) {
        this.name = name;
        this.age = age;
    }

    public String getName() {
        return name;
    }

    public int getAge() {
        return age;
    }

    @Override
    public String toString() {
        return "Employee{" + "name='" + name + '\'' + ", age=" + age + '}';
    }
}

public class EmployeeComparatorExample {
    public static void main(String[] args) {
        List<Employee> employees = new ArrayList<>();
        employees.add(new Employee("Alice", 30));
        employees.add(new Employee("Bob", 25));
        employees.add(new Employee("Charlie", 35));

        // Sort by name
        Collections.sort(employees, new Comparator<Employee>() {
            @Override
            public int compare(Employee e1, Employee e2) {
                return e1.getName().compareTo(e2.getName());
            }
        });

        System.out.println("Employees sorted by name: " + employees);

        // Sort by age
        Collections.sort(employees, new Comparator<Employee>() {
            @Override
            public int compare(Employee e1, Employee e2) {
                return Integer.compare(e1.getAge(), e2.getAge());
            }
        });

        System.out.println("Employees sorted by age: " + employees);
    }
}
//Output:


Employees sorted by name: [Employee{name='Alice', age=30},
Employee{name='Bob', age=25},
Employee{name='Charlie', age=35}]
Employees sorted by age: [Employee{name='Bob', age=25},
Employee{name='Alice', age=30},
Employee{name='Charlie', age=35}]

In this example, we first sort the list of employees by name and then by age using different comparators.

Lambda Expressions and Comparators

Since Java 8, you can use lambda expressions to simplify the creation of comparators. This makes the code cleaner and more readable.

Example: Using Lambda Expressions

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

public class LambdaComparatorExample {
    public static void main(String[] args) {
        List<Employee> employees = new ArrayList<>();
        employees.add(new Employee("Alice", 30));
        employees.add(new Employee("Bob", 25));
        employees.add(new Employee("Charlie", 35));

        // Sort by name using a lambda expression
        Collections.sort(employees, (e1, e2) -> e1.getName().compareTo(e2.getName()));
        System.out.println("Employees sorted by name (lambda): " + employees);

        // Sort by age using a lambda expression
        Collections.sort(employees, (e1, e2) -> Integer.compare(e1.getAge(), e2.getAge()));
        System.out.println("Employees sorted by age (lambda): " + employees);
    }
}
//Output:

Employees sorted by name (lambda): [Employee{name='Alice', age=30},
Employee{name='Bob', age=25},
Employee{name='Charlie', age=35}]
Employees sorted by age (lambda):
[Employee{name='Bob', age=25}, Employee{name='Alice',  age=30},
Employee{name='Charlie', age=35}]

Static Comparators Methods

Java 8 introduced several static methods in the Comparator interface that make it easier to create common comparators. Some of the most useful static methods include:

  1. Comparator.naturalOrder(): Returns a comparator that compares objects in their natural order.
  2. Comparator.reverseOrder(): Returns a comparator that reverses the natural ordering.
  3. Comparator.comparing(Function<? super T, ? extends U> keyExtractor): Returns a comparator that compares by a specified key.
  4. Comparator.comparingInt(ToIntFunction<? super T> keyExtractor): Similar to comparing, but for int values.

Example: Using Static Comparators Methods

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

public class StaticComparatorExample {
    public static void main(String[] args) {
        List<Employee> employees = new ArrayList<>();
        employees.add(new Employee("Alice", 30));
        employees.add(new Employee("Bob", 25));
        employees.add(new Employee("Charlie", 35));

        // Sort by name using static comparator method
        employees.sort(Comparator.comparing(Employee::getName));
        System.out.println("Employees sorted by name (static method): " + employees);

        // Sort by age using static comparator method
        employees.sort(Comparator.comparingInt(Employee::getAge));
        System.out.println("Employees sorted by age (static method): " + employees);
    }
}
//Output:

Employees sorted by name (static method):
[Employee{name='Alice', age=30},
Employee{name='Bob', age=25}, Employee{name='Charlie', age=35}]

Employees sorted by age (static method):
[Employee{name='Bob', age=25},Employee{name='Alice', age=30},
Employee{name='Charlie', age=35}]

Chaining Comparators

You can chain multiple comparators to sort by multiple criteria. This is particularly useful when you want to sort by one field and then by another field if the first field is equal.

Example: Chaining Comparators

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

public class ChainedComparatorExample {
    public static void main(String[] args) {
        List<Employee> employees = new ArrayList<>();
        employees.add(new Employee("Alice", 30));
        employees.add(new Employee("Bob", 25));
        employees.add(new Employee("Charlie", 25));
        employees.add(new Employee("Alice", 25));

        // Chained comparators: first by age, then by name
        Comparator<Employee> byAge = Comparator.comparingInt(Employee::getAge);
        Comparator<Employee> byName = Comparator.comparing(Employee::getName);
        Comparator<Employee> combinedComparator = byAge.thenComparing(byName);

        Collections.sort(employees, combinedComparator);
        System.out.println("Employees sorted by age and name: " + employees);
    }
}
//Output:

Employees sorted by age and name: [Employee{name='Alice',
age=25},Employee{name='Bob',age=25},
Employee{name='Alice', age=30},
Employee{name='Charlie', age=25}]

In this example, employees are sorted first by age and then by name if they have the same age.

Comparator with Collections

The Comparator interface is commonly used with various collection classes. Here are a few examples:

1. Using Comparator with a List

We’ve seen multiple examples of sorting lists using Comparator, but here’s a summary:

List<String> names = Arrays.asList("John", "Alice", "Bob");
Collections.sort(names, Comparator.naturalOrder());
System.out.println("Sorted names: " + names);

2. Using Comparator with a Set

When working with a TreeSet, you can provide a comparator at the time of creation:

Set<Employee> employeeSet = new TreeSet<>(Comparator.comparing(Employee::getName));
employeeSet.add(new Employee("Charlie", 35));
employeeSet.add(new Employee("Alice", 30));
employeeSet.add(new Employee("Bob", 25));

System.out.println("Employees in TreeSet: " + employeeSet);

3. Using Comparator with a Map

For sorting a Map by its keys or values, you can use a Comparator:

Map<String, Integer> map = new HashMap<>();
map.put("Alice", 30);
map.put("Bob", 25);
map.put("Charlie", 35);

// Sorting by keys
Map<String, Integer> sortedByKey = new TreeMap<>(Comparator.naturalOrder());
sortedByKey.putAll(map);
System.out.println("Sorted map by keys: " + sortedByKey);

Real-World Application of Comparators

Scenario: Sorting Products in an E-commerce Application

Let’s say you have an e-commerce application where you need to manage and sort a list of products based on various criteria such as price and name.

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

class Product {
    private String name;
    private double price;

    public Product(String name, double price) {
        this.name = name;
        this.price = price;
    }

    public String getName() {
        return name;
    }

    public double getPrice() {
        return price;
    }

    @Override
    public String toString() {
        return "Product{" + "name='" + name + '\'' + ", price=" + price + '}';
    }
}

public class ProductSortingExample {
    public static void main(String[] args) {
        List<Product> products = new ArrayList<>();
        products.add(new Product("Laptop", 999.99));
        products.add(new Product("Smartphone", 499.99));
        products.add(new Product("Tablet", 299.99));

        // Sort by price
        Collections.sort(products, Comparator.comparingDouble(Product::getPrice));
        System.out.println("Products sorted by price: " + products);

        // Sort by name
        Collections.sort(products, Comparator.comparing(Product::getName));
        System.out.println("Products sorted by name: " + products);
    }
}
//Output:

Products sorted by price:
[Product{name='Tablet', price=299.99},
Product{name='Smartphone', price=499.99},
Product{name='Laptop', price=999.99}]
Products sorted by name:
[Product{name='Laptop', price=999.99},
Product{name='Smartphone',price=499.99},
Product{name='Tablet', price=299.99}]

related topic

Treeset in java with example
Treeset in java with example In Java, a TreeSet is a part of the Java Collections Framework and implements...
java multilevel inheritance
Java multilevel inheritance Multilevel inheritance is a type of inheritance in which a class (child class)...
Java synchronization
Java synchronizations What is Synchronizations? Synchronizations in Java is a technique used to control...
Getter and setter in java
Getter and setter in java Getters in java A getter is a method that retrieves (or “gets”)...
Set in java (Interface)
Set in java example In Java, the Set interface is part of the Java Collections Framework and represents...
Java classes and object
Java classes and object Java is an object-oriented programming (OOP) language, which means that it is...
Filewriter in java with example
filewriter in java with example Writing to files in Java is a crucial skill for any developer, enabling...
Java Unary Operators
Java unary operators Unary operators in Java are some of the simplest yet most powerful tools available...
Comparator in java with example
comparator in java with example In Java, sorting collections of objects is a common task that often requires...
Singleton class java
Singleton class java with java The Singleton Design Pattern is a creational design pattern that restricts...