Skip to main content
Java

How to write Comparator in Java?

— Aakash Verma

Introduction

We often get confused while writing comparators. Here, we provide you with an in-detailed guide on How to write a comparator in Java. We will focus on writing comparators using List or ArrayList, PriorityQueue (MinHeap or MaxHeap), and Map in Java.

💡
For better understanding, we highly recommend observing input in each scenario because there are some changes in every scenario.

In this article, we will use the Student object below to explain.

package in.innoskrit.comparator;

public class Student {
    String name;
    int position;
    int age;

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

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

Mastering Comparator on List

Sort a list of Student based on their name.

package com.interview.comparator;

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

public class Driver {
    public static void main(String[] args) {
        Student s1 = new Student("Sam", 2, 15);
        Student s2 = new Student("Ken", 1, 14);
        Student s3 = new Student("Paul", 2, 12);
        Student s4 = new Student("Jennie", 3, 16);
        Student s5 = new Student("Hana", 1, 17);
        Student s6 = new Student("Clark", 4, 18);
        Student s7 = new Student("Jimmy", 5, 19);

        List<Student> students = new ArrayList<>();
        students.add(s1);
        students.add(s2);
        students.add(s3);
        students.add(s4);
        students.add(s5);
        students.add(s6);
        students.add(s7);

        students.sort(Comparator.comparing((Student s) -> s.name));
        // students.sort(Comparator.comparing(s -> s.name)); this will also work

        for(Student student : students) {
            System.out.println(student.toString());
        }

    }
}

Output

Student{name='Clark', position=4, age=18}
Student{name='Hana', position=1, age=17}
Student{name='Jennie', position=3, age=16}
Student{name='Jimmy', position=5, age=19}
Student{name='Ken', position=1, age=14}
Student{name='Paul', position=2, age=12}
Student{name='Sam', position=2, age=15}

Sort a list of Student based on their position.

package in.innoskrit.comparator;

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

public class Driver {
    public static void main(String[] args) {
        Student s1 = new Student("Sam", 2, 15);
        Student s2 = new Student("Ken", 1, 14);
        Student s3 = new Student("Paul", 2, 12);
        Student s4 = new Student("Jennie", 3, 16);
        Student s5 = new Student("Hana", 1, 17);
        Student s6 = new Student("Clark", 4, 18);
        Student s7 = new Student("Jimmy", 5, 19);

        List<Student> students = new ArrayList<>();
        students.add(s1);
        students.add(s2);
        students.add(s3);
        students.add(s4);
        students.add(s5);
        students.add(s6);
        students.add(s7);

        students.sort(Comparator.comparingInt((Student s) -> s.position));
        // students.sort(Comparator.comparingInt(s -> s.position)); this will also work

        for(Student student : students) {
            System.out.println(student.toString());
        }

    }
}

Output

Student{name='Ken', position=1, age=14}
Student{name='Hana', position=1, age=17}
Student{name='Sam', position=2, age=15}
Student{name='Paul', position=2, age=12}
Student{name='Jennie', position=3, age=16}
Student{name='Clark', position=4, age=18}
Student{name='Jimmy', position=5, age=19}

As you can see, the students are sorted based on their positions. Now, for each equal position, we want to sort it further based on their names.

Sort a list of Student based on their position, and if positions are equal, then sort it based on their names in lexicographically sorted order.

package com.interview.comparator;

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

public class Driver {
    public static void main(String[] args) {
        Student s1 = new Student("Sam", 2, 15);
        Student s2 = new Student("Ken", 1, 14);
        Student s3 = new Student("Paul", 2, 12);
        Student s4 = new Student("Jennie", 3, 16);
        Student s5 = new Student("Hana", 1, 17);
        Student s6 = new Student("Clark", 4, 18);
        Student s7 = new Student("Jimmy", 5, 19);

        List<Student> students = new ArrayList<>();
        students.add(s1);
        students.add(s2);
        students.add(s3);
        students.add(s4);
        students.add(s5);
        students.add(s6);
        students.add(s7);


        students.sort(Comparator.comparingInt((Student s) -> s.position)
                .thenComparing(s -> s.name));

        for(Student student : students) {
            System.out.println(student.toString());
        }

    }
}

Output

Student{name='Hana', position=1, age=17}
Student{name='Ken', position=1, age=14}
Student{name='Paul', position=2, age=12}
Student{name='Sam', position=2, age=15}
Student{name='Jennie', position=3, age=16}
Student{name='Clark', position=4, age=18}
Student{name='Jimmy', position=5, age=19}
💡
NOTE: If you will try to sort the above list of Students using the below code snippet. It won't work. The compiler may not correctly infer that s is of type Student for the thenComparing method, leading to a compilation error. This can happen because the type inference might not be strong enough to handle the chained comparators correctly in this context. Hence, you need to mention explicitly (Student s) -> s.position so that thenComparing identifies s correctly.
students.sort(Comparator.comparingInt(s -> s.position) .thenComparing(s -> s.name));

Sort a list of Student based on their position, and if positions are equal, then sort it based on their names in lexicographically sorted order. And if names are the same, then sort them based on their age.

package com.interview.comparator;

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

public class Driver {
    public static void main(String[] args) {
        Student s1 = new Student("Sam", 2, 15);
        Student s2 = new Student("Hana", 1, 17);
        Student s3 = new Student("Paul", 2, 12);
        Student s4 = new Student("Jennie", 3, 16);
        Student s5 = new Student("Hana", 1, 14);
        Student s6 = new Student("Clark", 4, 18);
        Student s7 = new Student("Jimmy", 5, 19);
        Student s8 = new Student("Ken", 1, 15);

        List<Student> students = new ArrayList<>();
        students.add(s1);
        students.add(s2);
        students.add(s3);
        students.add(s4);
        students.add(s5);
        students.add(s6);
        students.add(s7);
        students.add(s8);

        students.sort(Comparator.comparing((Student s) -> s.position)
                .thenComparing(s -> s.name)
                .thenComparing(s -> s.age));

        for(Student student : students) {
            System.out.println(student.toString());
        }

    }
}

Output

Student{name='Hana', position=1, age=17}
Student{name='Hana', position=1, age=14}
Student{name='Ken', position=1, age=15}
Student{name='Paul', position=2, age=12}
Student{name='Sam', position=2, age=15}
Student{name='Jennie', position=3, age=16}
Student{name='Clark', position=4, age=18}
Student{name='Jimmy', position=5, age=19}

Sort a list of Student based on their position, and if positions are equal, then sort it based on their names in lexicographically sorted order. And if names are the same, then sort them based on their age in decreasing order.

package com.interview.comparator;

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

public class Driver {
    public static void main(String[] args) {
        Student s1 = new Student("Sam", 2, 15);
        Student s2 = new Student("Hana", 1, 17);
        Student s3 = new Student("Paul", 2, 12);
        Student s4 = new Student("Jennie", 3, 16);
        Student s5 = new Student("Hana", 1, 14);
        Student s6 = new Student("Clark", 4, 18);
        Student s7 = new Student("Jimmy", 5, 19);
        Student s8 = new Student("Ken", 1, 15);

        List<Student> students = new ArrayList<>();
        students.add(s1);
        students.add(s2);
        students.add(s3);
        students.add(s4);
        students.add(s5);
        students.add(s6);
        students.add(s7);
        students.add(s8);

        students.sort(Comparator.comparing((Student s) -> s.position)
                .thenComparing(s -> s.name)
                .thenComparing(s -> -1 * s.age)); // can also be replaced by .thenComparing(s -> s.age, Comparator.reverseOrder()));

        for(Student student : students) {
            System.out.println(student.toString());
        }

    }
}

Output

Student{name='Hana', position=1, age=17}
Student{name='Hana', position=1, age=14}
Student{name='Ken', position=1, age=15}
Student{name='Paul', position=2, age=12}
Student{name='Sam', position=2, age=15}
Student{name='Jennie', position=3, age=16}
Student{name='Clark', position=4, age=18}
Student{name='Jimmy', position=5, age=19}

Sort a list of Student based on their position, and if positions are equal, then sort it based on their names in reverse lexicographically sorted order.

package com.interview.comparator;

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

public class Driver {
    public static void main(String[] args) {
        Student s1 = new Student("Sam", 2, 15);
        Student s2 = new Student("Hana", 1, 17);
        Student s3 = new Student("Paul", 2, 12);
        Student s4 = new Student("Jennie", 3, 16);
        Student s5 = new Student("Hana", 1, 14);
        Student s6 = new Student("Clark", 4, 18);
        Student s7 = new Student("Jimmy", 5, 19);
        Student s8 = new Student("Ken", 1, 15);

        List<Student> students = new ArrayList<>();
        students.add(s1);
        students.add(s2);
        students.add(s3);
        students.add(s4);
        students.add(s5);
        students.add(s6);
        students.add(s7);
        students.add(s8);

        students.sort(Comparator.comparing((Student s) -> s.position)
                .thenComparing(Comparator.comparing((Student s) -> s.name).reversed()));
                
                
//        students.sort(Comparator.comparing((Student s) -> s.position)
//                .thenComparing(s -> s.name, Comparator.reverseOrder()));
//        you can also write this like this, just pass Comparator.reverseOrder() as a second argument to the thenComparing() method.

        for(Student student : students) {
            System.out.println(student.toString());
        }

    }
}

Output

Student{name='Ken', position=1, age=15}
Student{name='Hana', position=1, age=17}
Student{name='Hana', position=1, age=14}
Student{name='Sam', position=2, age=15}
Student{name='Paul', position=2, age=12}
Student{name='Jennie', position=3, age=16}
Student{name='Clark', position=4, age=18}
Student{name='Jimmy', position=5, age=19}

Mastering Comparator on PriorityQueue

Creating a minHeap of Student based on their position

package in.innoskrit;

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

class Student {
    String name;
    int position;
    int age;

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

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

public class Main {
    public static void main(String[] args) {
        Student s1 = new Student("Sam", 2, 15);
        Student s2 = new Student("Ken", 1, 14);
        Student s3 = new Student("Paul", 2, 12);
        Student s4 = new Student("Jennie", 3, 16);
        Student s5 = new Student("Hana", 1, 17);
        Student s6 = new Student("Clark", 4, 18);
        Student s7 = new Student("Jimmy", 5, 19);

        List<Student> students = new ArrayList<>();
        students.add(s1);
        students.add(s2);
        students.add(s3);
        students.add(s4);
        students.add(s5);
        students.add(s6);
        students.add(s7);

        PriorityQueue<Student> minHeap = new PriorityQueue<>(Comparator.comparingInt(s -> s.position));
        for(Student student : students) {
            minHeap.offer(student);
        }

        Student minHeapPeek = minHeap.peek();
        System.out.println(minHeapPeek.name + " " + minHeapPeek.position + " " + minHeapPeek.age);
    }
}

Output

Ken 1 14

Creating a maxHeap of Student based on their position

package in.innoskrit;

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

class Student {
    String name;
    int position;
    int age;

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

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

public class Main {
    public static void main(String[] args) {
        Student s1 = new Student("Sam", 2, 15);
        Student s2 = new Student("Ken", 1, 14);
        Student s3 = new Student("Paul", 2, 12);
        Student s4 = new Student("Jennie", 3, 16);
        Student s5 = new Student("Hana", 1, 17);
        Student s6 = new Student("Clark", 4, 18);
        Student s7 = new Student("Jimmy", 5, 19);

        List<Student> students = new ArrayList<>();
        students.add(s1);
        students.add(s2);
        students.add(s3);
        students.add(s4);
        students.add(s5);
        students.add(s6);
        students.add(s7);

        PriorityQueue<Student> minHeap = new PriorityQueue<>(Comparator.comparingInt((Student s) -> s.position).reversed());
        for(Student student : students) {
            minHeap.offer(student);
        }

        Student minHeapPeek = minHeap.peek();
        System.out.println(minHeapPeek.name + " " + minHeapPeek.position + " " + minHeapPeek.age);
    }
}

Output

Jimmy 5 19

Creating a minHeap of Student based on position and if positions are the same then names in lexicographically sorted order.

package in.innoskrit;

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

class Student {
    String name;
    int position;
    int age;

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

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

public class Main {
    public static void main(String[] args) {
        Student s1 = new Student("Sam", 2, 15);
        Student s2 = new Student("Ken", 1, 14);
        Student s3 = new Student("Paul", 2, 12);
        Student s4 = new Student("Jennie", 3, 16);
        Student s5 = new Student("Hana", 1, 17);
        Student s6 = new Student("Clark", 4, 18);
        Student s7 = new Student("Jimmy", 5, 19);

        List<Student> students = new ArrayList<>();
        students.add(s1);
        students.add(s2);
        students.add(s3);
        students.add(s4);
        students.add(s5);
        students.add(s6);
        students.add(s7);

        PriorityQueue<Student> minHeap = new PriorityQueue<>(Comparator.comparingInt((Student s) -> s.position)
                        .thenComparing(s -> s.name));
        
        for(Student student : students) {
            minHeap.offer(student);
        }

        Student minHeapPeek = minHeap.peek();
        System.out.println(minHeapPeek.name + " " + minHeapPeek.position + " " + minHeapPeek.age);
    }
}

Output

Hana 1 17

Creating a minHeap of Student based on position and if positions are the same then names in reverse lexicographically sorted order.

package in.innoskrit;

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

class Student {
    String name;
    int position;
    int age;

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

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

public class Main {
    public static void main(String[] args) {
        Student s1 = new Student("Sam", 2, 15);
        Student s2 = new Student("Ken", 1, 14);
        Student s3 = new Student("Paul", 2, 12);
        Student s4 = new Student("Jennie", 3, 16);
        Student s5 = new Student("Hana", 1, 17);
        Student s6 = new Student("Clark", 4, 18);
        Student s7 = new Student("Jimmy", 5, 19);

        List<Student> students = new ArrayList<>();
        students.add(s1);
        students.add(s2);
        students.add(s3);
        students.add(s4);
        students.add(s5);
        students.add(s6);
        students.add(s7);

        PriorityQueue<Student> minHeap = new PriorityQueue<>(Comparator.comparingInt((Student s) -> s.position)
                        .thenComparing(Comparator.comparing((Student s) -> s.name).reversed()));
                        
//        you can also write this like this, just pass Comparator.reverseOrder() as a second argument to the thenComparing() method.

        for(Student student : students) {
            minHeap.offer(student);
        }

        Student minHeapPeek = minHeap.peek();
        System.out.println(minHeapPeek.name + " " + minHeapPeek.position + " " + minHeapPeek.age);
    }
}

Output

Ken 1 14

Creating a maxHeap of Student based on position and if positions are the same then names in lexicographically sorted order.

package in.innoskrit;

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

class Student {
    String name;
    int position;
    int age;

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

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

public class Main {
    public static void main(String[] args) {
        Student s1 = new Student("Sam", 2, 15);
        Student s2 = new Student("Ken", 1, 14);
        Student s3 = new Student("Paul", 2, 12);
        Student s4 = new Student("Jennie", 3, 16);
        Student s5 = new Student("Hana", 1, 17);
        Student s6 = new Student("Clark", 4, 18);
        Student s7 = new Student("Jimmy", 5, 19);
        Student s8 = new Student("Zen", 5, 20);

        List<Student> students = new ArrayList<>();
        students.add(s1);
        students.add(s2);
        students.add(s3);
        students.add(s4);
        students.add(s5);
        students.add(s6);
        students.add(s7);
        students.add(s8);

        PriorityQueue<Student> maxHeap = new PriorityQueue<>(Comparator.comparingInt((Student s) -> s.position).reversed()
                .thenComparing(s -> s.name));

        for(Student student : students) {
            maxHeap.offer(student);
        }

        Student maxHeapPeek = maxHeap.peek();
        System.out.println(maxHeapPeek.name + " " + maxHeapPeek.position + " " + maxHeapPeek.age);
    }
}

Output

Jimmy 5 19

Creating a maxHeap of Student based on position and if positions are same then names in reverse lexicographically sorted order.

package in.innoskrit;

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

class Student {
    String name;
    int position;
    int age;

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

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

public class Main {
    public static void main(String[] args) {
        Student s1 = new Student("Sam", 2, 15);
        Student s2 = new Student("Ken", 1, 14);
        Student s3 = new Student("Paul", 2, 12);
        Student s4 = new Student("Jennie", 3, 16);
        Student s5 = new Student("Hana", 1, 17);
        Student s6 = new Student("Clark", 4, 18);
        Student s7 = new Student("Jimmy", 5, 19);
        Student s8 = new Student("Zen", 5, 20);

        List<Student> students = new ArrayList<>();
        students.add(s1);
        students.add(s2);
        students.add(s3);
        students.add(s4);
        students.add(s5);
        students.add(s6);
        students.add(s7);
        students.add(s8);

        PriorityQueue<Student> maxHeap = new PriorityQueue<>(Comparator.comparingInt((Student s) -> s.position).reversed()
                .thenComparing(s -> s.name, Comparator.reverseOrder()));

        for(Student student : students) {
            maxHeap.offer(student);
        }

        Student maxHeapPeek = maxHeap.peek();
        System.out.println(maxHeapPeek.name + " " + maxHeapPeek.position + " " + maxHeapPeek.age);
    }
}

Output

Zen 5 20

Mastering Comparator on Map

Coming Soon...