Voorbeeld van Comparable en Comparator in Java

Comparable en Comparator in Java zijn erg handig voor het sorteren van collecties van objecten. Java biedt enkele ingebouwde methoden om arrays of lijsten van primitieve typen of Wrapper-klassen te sorteren. Hier zullen we eerst leren hoe we een array/lijst van primitieve typen en Wrapper-klassen kunnen sorteren, en vervolgens zullen we de interfaces java.lang.Comparable en java.util.Comparator gebruiken om een array/lijst van aangepaste klassen te sorteren. Laten we eens kijken hoe we primitieve typen of objectarrays en lijsten kunnen sorteren met een eenvoudig programma.

package com.journaldev.sort;

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

public class JavaObjectSorting {

    /**
     * This class shows how to sort primitive arrays, 
     * Wrapper classes Object Arrays
     * @param args
     */
    public static void main(String[] args) {
        //sorteer primitieve array zoals int array
        int[] intArr = {5,9,1,10};
        Arrays.sort(intArr);
        System.out.println(Arrays.toString(intArr));
        
        //sorteer String array
        String[] strArr = {"A", "C", "B", "Z", "E"};
        Arrays.sort(strArr);
        System.out.println(Arrays.toString(strArr));
        
        //sorteer lijst van objecten van Wrapper-klassen
        List strList = new ArrayList();
        strList.add("A");
        strList.add("C");
        strList.add("B");
        strList.add("Z");
        strList.add("E");
        Collections.sort(strList);
        for(String str: strList) System.out.print(" "+str);
    }
}

De uitvoer van het bovenstaande programma is:

[1, 5, 9, 10]
[A, B, C, E, Z]
 A B C E Z

Laten we nu proberen om een array van objecten te sorteren.

package com.journaldev.sort;

public class Employee {

    private int id;
    private String name;
    private int age;
    private long salary;

    public int getId() {
        return id;
    }

    public String getName() {
        return name;
    }

    public int getAge() {
        return age;
    }

    public long getSalary() {
        return salary;
    }

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

    @Override
    //dit is overschreven om informatie over de Employee op een gebruiksvriendelijke manier af te drukken
    public String toString() {
        return "[id=" + this.id + ", name=" + this.name + ", age=" + this.age + ", salary=" +
                this.salary + "]";
    }

}

Hier is de code die ik gebruikte om de array van Employee-objecten te sorteren.

//sorteer objectarray
Employee[] empArr = new Employee[4];
empArr[0] = new Employee(10, "Mikey", 25, 10000);
empArr[1] = new Employee(20, "Arun", 29, 20000);
empArr[2] = new Employee(5, "Lisa", 35, 5000);
empArr[3] = new Employee(1, "Pankaj", 32, 50000);

//sorteer employees-array met behulp van Comparable-interface-implementatie
Arrays.sort(empArr);
System.out.println("Default Sorting of Employees list:\n"+Arrays.toString(empArr));

Toen ik dit probeerde uit te voeren, gooide het de volgende runtime-uitzondering.

Exception in thread "main" java.lang.ClassCastException: com.journaldev.sort.Employee cannot be cast to java.lang.Comparable
	at java.util.ComparableTimSort.countRunAndMakeAscending(ComparableTimSort.java:290)
	at java.util.ComparableTimSort.sort(ComparableTimSort.java:157)
	at java.util.ComparableTimSort.sort(ComparableTimSort.java:146)
	at java.util.Arrays.sort(Arrays.java:472)
	at com.journaldev.sort.JavaSorting.main(JavaSorting.java:41)

Comparable en Comparator

Java biedt het Comparable-interface dat geïmplementeerd moet worden door elke aangepaste klasse als we de sorteermethoden van Arrays of Collections willen gebruiken. Het Comparable-interface heeft de methode compareTo(T obj) die gebruikt wordt door sorteermethoden; je kunt elke Wrapper-, String- of Date-klasse controleren om dit te bevestigen. We moeten deze methode overschrijven op zo’n manier dat het een negatief geheel getal, nul, of een positief geheel getal retourneert als “dit” object respectievelijk kleiner dan, gelijk aan, of groter dan het object is dat als argument wordt doorgegeven. Na het implementeren van Comparable interface in de Employee-klasse, is hier de resulterende Employee-klasse.

package com.journaldev.sort;

import java.util.Comparator;

public class Employee implements Comparable {

    private int id;
    private String name;
    private int age;
    private long salary;

    public int getId() {
        return id;
    }

    public String getName() {
        return name;
    }

    public int getAge() {
        return age;
    }

    public long getSalary() {
        return salary;
    }

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

    @Override
    public int compareTo(Employee emp) {
        // laten we de werknemers sorteren op id in oplopende volgorde
        // retourneert een negatief geheel getal, nul, of een positief geheel getal als dit werknemers-id
        // respectievelijk kleiner dan, gelijk aan, of groter is dan het gespecificeerde object.
        return (this.id - emp.id);
    }

    @Override
    // dit is vereist om de gebruikersvriendelijke informatie over de werknemer af te drukken
    public String toString() {
        return "[id=" + this.id + ", name=" + this.name + ", age=" + this.age + ", salary=" +
                this.salary + "]";
    }

}

Nu wanneer we het bovenstaande fragment uitvoeren voor de Arrays-sortering van werknemers en het afdrukken, is hier de uitvoer.

Default Sorting of Employees list:
[[id=1, name=Pankaj, age=32, salary=50000], [id=5, name=Lisa, age=35, salary=5000], [id=10, name=Mikey, age=25, salary=10000], [id=20, name=Arun, age=29, salary=20000]]

Zoals je kunt zien, is de Employees-array gesorteerd op id in oplopende volgorde. Maar in de meeste realistische scenario’s willen we sorteren op basis van verschillende parameters. Bijvoorbeeld, als CEO zou ik de werknemers willen sorteren op basis van salaris, een HR-medewerker zou ze willen sorteren op leeftijd. Dit is de situatie waarin we de Java Comparator-interface moeten gebruiken omdat de implementatie van de Comparable.compareTo(Object o)-methode standaardsortering kan bieden en we deze niet dynamisch kunnen wijzigen. Met Comparator kunnen we daarentegen meerdere methoden definiëren met verschillende sorteermethoden en vervolgens de sorteermethode kiezen op basis van onze vereisten.

Java Comparator

Comparator-interface compare(Object o1, Object o2)-methode moet worden geïmplementeerd die twee Object-argumenten aanneemt. Het moet zo worden geïmplementeerd dat het een negatieve integer retourneert als het eerste argument kleiner is dan het tweede, nul retourneert als ze gelijk zijn en een positieve integer als het eerste argument groter is dan het tweede. Comparable en Comparator interfaces gebruiken Generics voor typecontrole op compileertijd, leer meer over Java Generics. Zo kunnen we verschillende Comparator-implementaties maken in de Employee-klasse.

/**
     * Comparator to sort employees list or array in order of Salary
     */
    public static Comparator<Employee> SalaryComparator = new Comparator<Employee>() {

        @Override
        public int compare(Employee e1, Employee e2) {
            return (int) (e1.getSalary() - e2.getSalary());
        }
    };

    /**
     * Comparator to sort employees list or array in order of Age
     */
    public static Comparator<Employee> AgeComparator = new Comparator<Employee>() {

        @Override
        public int compare(Employee e1, Employee e2) {
            return e1.getAge() - e2.getAge();
        }
    };

    /**
     * Comparator to sort employees list or array in order of Name
     */
    public static Comparator<Employee> NameComparator = new Comparator<Employee>() {

        @Override
        public int compare(Employee e1, Employee e2) {
            return e1.getName().compareTo(e2.getName());
        }
    };

Alle bovenstaande implementaties van de Comparator-interface zijn anonieme klassen. We kunnen deze comparators gebruiken om een argument door te geven aan de sorteerfunctie van de Arrays- en Collections-klassen.

// sorteer de array van werknemers met behulp van Comparator op salaris
Arrays.sort(empArr, Employee.SalaryComparator);
System.out.println("Employees list sorted by Salary:\n"+Arrays.toString(empArr));

// sorteer de array van werknemers met behulp van Comparator op leeftijd
Arrays.sort(empArr, Employee.AgeComparator);
System.out.println("Employees list sorted by Age:\n"+Arrays.toString(empArr));

// sorteer de array van werknemers met behulp van Comparator op naam
Arrays.sort(empArr, Employee.NameComparator);
System.out.println("Employees list sorted by Name:\n"+Arrays.toString(empArr));

Hier is de output van het bovenstaande codefragment:

Employees list sorted by Salary:
[[id=5, name=Lisa, age=35, salary=5000], [id=10, name=Mikey, age=25, salary=10000], [id=20, name=Arun, age=29, salary=20000], [id=1, name=Pankaj, age=32, salary=50000]]
Employees list sorted by Age:
[[id=10, name=Mikey, age=25, salary=10000], [id=20, name=Arun, age=29, salary=20000], [id=1, name=Pankaj, age=32, salary=50000], [id=5, name=Lisa, age=35, salary=5000]]
Employees list sorted by Name:
[[id=20, name=Arun, age=29, salary=20000], [id=5, name=Lisa, age=35, salary=5000], [id=10, name=Mikey, age=25, salary=10000], [id=1, name=Pankaj, age=32, salary=50000]]

Dus nu weten we dat als we een Java-objectarray of -lijst willen sorteren, we de Java Comparable-interface moeten implementeren om standaard sortering te bieden en we moeten de Java Comparator-interface implementeren om verschillende manieren van sorteren te bieden. We kunnen ook een aparte klasse maken die de Comparator-interface implementeert en deze vervolgens gebruiken. Hier zijn de uiteindelijke klassen die Comparable en Comparator in Java uitleggen.

package com.journaldev.sort;

import java.util.Comparator;

public class Employee implements Comparable {

    private int id;
    private String name;
    private int age;
    private long salary;

    public int getId() {
        return id;
    }

    public String getName() {
        return name;
    }

    public int getAge() {
        return age;
    }

    public long getSalary() {
        return salary;
    }

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

    @Override
    public int compareTo(Employee emp) {
        // laten we de werknemer sorteren op basis van een id in oplopende volgorde
        // geeft een negatief getal, nul, of een positief getal terug als deze werknemer id
        // kleiner is dan, gelijk aan, of groter is dan het gespecificeerde object.
        return (this.id - emp.id);
    }

    @Override
    // dit is vereist om de gebruikersvriendelijke informatie over de werknemer af te drukken
    public String toString() {
        return "[id=" + this.id + ", name=" + this.name + ", age=" + this.age + ", salary=" +
                this.salary + "]";
    }

    /**
     * Comparator to sort employees list or array in order of Salary
     */
    public static Comparator SalaryComparator = new Comparator() {

        @Override
        public int compare(Employee e1, Employee e2) {
            return (int) (e1.getSalary() - e2.getSalary());
        }
    };

    /**
     * Comparator to sort employees list or array in order of Age
     */
    public static Comparator AgeComparator = new Comparator() {

        @Override
        public int compare(Employee e1, Employee e2) {
            return e1.getAge() - e2.getAge();
        }
    };

    /**
     * Comparator to sort employees list or array in order of Name
     */
    public static Comparator NameComparator = new Comparator() {

        @Override
        public int compare(Employee e1, Employee e2) {
            return e1.getName().compareTo(e2.getName());
        }
    };
}

Hier is de afzonderlijke klassenimplementatie van de Comparator-interface die twee Employee-objecten vergelijkt, eerst op hun id en als ze hetzelfde zijn, op de naam.

package com.journaldev.sort;

import java.util.Comparator;

public class EmployeeComparatorByIdAndName implements Comparator<Employee> {

    @Override
    public int compare(Employee o1, Employee o2) {
        int flag = o1.getId() - o2.getId();
        if(flag==0) flag = o1.getName().compareTo(o2.getName());
        return flag;
    }

}

Hier is de testklasse waarin we verschillende manieren gebruiken om objecten in Java te sorteren met behulp van Comparable en Comparator.

package com.journaldev.sort;

import java.util.Arrays;

public class JavaObjectSorting {

    /**
     * This class shows how to sort custom objects array/list
     * implementing Comparable and Comparator interfaces
     * @param args
     */
    public static void main(String[] args) {

        //sorteren van aangepaste object array
        Employee[] empArr = new Employee[4];
        empArr[0] = new Employee(10, "Mikey", 25, 10000);
        empArr[1] = new Employee(20, "Arun", 29, 20000);
        empArr[2] = new Employee(5, "Lisa", 35, 5000);
        empArr[3] = new Employee(1, "Pankaj", 32, 50000);
        
        //sorteer werknemersarray met Comparable-interface-implementatie
        Arrays.sort(empArr);
        System.out.println("Default Sorting of Employees list:\n"+Arrays.toString(empArr));
        
        //sorteer werknemersarray met Comparator op salaris
        Arrays.sort(empArr, Employee.SalaryComparator);
        System.out.println("Employees list sorted by Salary:\n"+Arrays.toString(empArr));
        
        //sorteer werknemersarray met Comparator op leeftijd
        Arrays.sort(empArr, Employee.AgeComparator);
        System.out.println("Employees list sorted by Age:\n"+Arrays.toString(empArr));
        
        //sorteer werknemersarray met Comparator op naam
        Arrays.sort(empArr, Employee.NameComparator);
        System.out.println("Employees list sorted by Name:\n"+Arrays.toString(empArr));
        
        //Werknemerslijst gesorteerd op ID en vervolgens op naam met behulp van Comparator-klasse
        empArr[0] = new Employee(1, "Mikey", 25, 10000);
        Arrays.sort(empArr, new EmployeeComparatorByIdAndName());
        System.out.println("Employees list sorted by ID and Name:\n"+Arrays.toString(empArr));
    }

}

Hier is de uitvoer van het bovenstaande programma:

Default Sorting of Employees list:
[[id=1, name=Pankaj, age=32, salary=50000], [id=5, name=Lisa, age=35, salary=5000], [id=10, name=Mikey, age=25, salary=10000], [id=20, name=Arun, age=29, salary=20000]]
Employees list sorted by Salary:
[[id=5, name=Lisa, age=35, salary=5000], [id=10, name=Mikey, age=25, salary=10000], [id=20, name=Arun, age=29, salary=20000], [id=1, name=Pankaj, age=32, salary=50000]]
Employees list sorted by Age:
[[id=10, name=Mikey, age=25, salary=10000], [id=20, name=Arun, age=29, salary=20000], [id=1, name=Pankaj, age=32, salary=50000], [id=5, name=Lisa, age=35, salary=5000]]
Employees list sorted by Name:
[[id=20, name=Arun, age=29, salary=20000], [id=5, name=Lisa, age=35, salary=5000], [id=10, name=Mikey, age=25, salary=10000], [id=1, name=Pankaj, age=32, salary=50000]]
Employees list sorted by ID and Name:
[[id=1, name=Mikey, age=25, salary=10000], [id=1, name=Pankaj, age=32, salary=50000], [id=5, name=Lisa, age=35, salary=5000], [id=10, name=Mikey, age=25, salary=10000]]

De java.lang.Comparable en java.util.Comparator zijn krachtige interfaces die kunnen worden gebruikt om objecten in Java te sorteren.

Comparable vs Comparator

  1. Comparable-interface kan worden gebruikt om op één manier te sorteren, terwijl de Comparator-interface wordt gebruikt om op verschillende manieren te sorteren.
  2. Om Comparable te gebruiken, moet de klasse het implementeren, terwijl we voor Comparator geen wijzigingen in de klasse hoeven aan te brengen.
  3. Comparable-interface bevindt zich in het pakket java.lang, terwijl de Comparator-interface aanwezig is in het pakket java.util.
  4. We hoeven geen code wijzigingen aan te brengen aan de klantzijde voor het gebruik van Comparable, Arrays.sort() of Collection.sort() methoden gebruiken automatisch de compareTo()-methode van de klasse. Voor Comparator moet de klant de Comparator-klasse opgeven om te gebruiken in de compare()-methode.

Weet je dat de Collections.sort() methode die een Comparator argument gebruikt het Strategy Patroon volgt?

Je kunt de volledige code en meer voorbeelden van core java vinden op onze GitHub Repository.

Source:
https://www.digitalocean.com/community/tutorials/comparable-and-comparator-in-java-example