美文网首页
Java Comparable和Comparator接口

Java Comparable和Comparator接口

作者: 程序员will | 来源:发表于2019-08-14 10:11 被阅读0次

    Java Comparable和Comparator接口

    我们经常需要在Java程序中比较两个值。比较原始值如intcharfloat是很容易的,像<>==`等。

    但比较对象有点不同。例如,您如何比较两名员工?你会如何比较两个学生?

    您需要明确定义应如何比较用户定义类的对象。为此,Java提供了两个名为Comparable和的接口Comparator

    一旦定义了如何使用任何这些接口比较对象,您就可以使用各种库函数(如Collections.sort或)对它们进行排序Arrays.sort

    [TOC]

    Java Comparable接口

    默认情况下,用户定义的类不具有可比性。也就是说,它的对象无法进行比较。要使对象具有可比性,该类必须实现该Comparable接口。

    Comparable接口有一个称为一个方法compareTo(),你需要以定义对象如何与所提供的对象进行比较来实现-

    public interface Comparable<T> {
         public int compareTo(T o);
    }
    

    compareTo()在类中定义方法时,需要确保此方法的返回值为 -

    • negative,如果此对象小于提供的对象。
    • zero,如果此对象等于提供的对象。
    • positive,如果此对象大于提供的对象。

    许多预定义的Java类,如StringDateLocalDateLocalDateTime等落实Comparable来定义它们的实例的排序界面。

    现在让我们看一个让事情更清晰的例子。

    Java Comparable接口示例

    下面的示例显示如何Comparable在用户定义的类中实现接口,并定义compareTo()使该类的对象具有可比性的方法。

    import java.time.LocalDate;
    import java.util.Objects;
    
    class Employee implements Comparable<Employee> {
        private int id;
        private String name;
        private double salary;
        private LocalDate joiningDate;
    
        public Employee(int id, String name, double salary, LocalDate joiningDate) {
            this.id = id;
            this.name = name;
            this.salary = salary;
            this.joiningDate = joiningDate;
        }
    
        public int getId() {
            return id;
        }
    
        public void setId(int id) {
            this.id = id;
        }
    
        public String getName() {
            return name;
        }
    
        public void setName(String name) {
            this.name = name;
        }
    
        public double getSalary() {
            return salary;
        }
    
        public void setSalary(double salary) {
            this.salary = salary;
        }
    
        public LocalDate getJoiningDate() {
            return joiningDate;
        }
    
        public void setJoiningDate(LocalDate joiningDate) {
            this.joiningDate = joiningDate;
        }
    
        // Compare Two Employees based on their ID
        /**
         * @param   anotherEmployee - The Employee to be compared.
         * @return  A negative integer, zero, or a positive integer as this employee
         *          is less than, equal to, or greater than the supplied employee object.
        */
        @Override
        public int compareTo(Employee anotherEmployee) {
            return this.getId() - anotherEmployee.getId();
        }
    
        // Two employees are equal if their IDs are equal
        @Override
        public boolean equals(Object o) {
            if (this == o) return true;
            if (o == null || getClass() != o.getClass()) return false;
            Employee employee = (Employee) o;
            return id == employee.id;
        }
    
        @Override
        public int hashCode() {
            return Objects.hash(id);
        }
    
        @Override
        public String toString() {
            return "Employee{" +
                    "id=" + id +
                    ", name='" + name + '\'' +
                    ", salary=" + salary +
                    ", joiningDate=" + joiningDate +
                    '}';
        }
    }
    

    在上面的示例中,我们通过ID来比较两个员工。

    我们只是在返回this.getId() - anotherEmployee.getId()compareTo()功能,这将是

    • negative 如果该员工的ID小于所提供员工的ID,
    • zero 如果该员工的ID等于所提供员工的ID,和
    • positive 如果此员工的ID大于所提供员工的ID。

    这只是撰写以下内容的简洁方式 -

    public int compareTo(Employee anotherEmployee) {
        if(this.getId() < anotherEmployee.getId()) {
            return -1;
        } else if (this.getId() > anotherEmployee.getId()) {
            return 1;
        } else {
            return 0;
        }
    }
    

    现在让我们看看如何Employee通过Collections.sort方法自动对对象进行排序

    import java.time.LocalDate;
    import java.util.ArrayList;
    import java.util.Collections;
    import java.util.Comparator;
    import java.util.List;
    
    public class ComparableExample {
        public static void main(String[] args) {
            List<Employee> employees = new ArrayList<>();
    
            employees.add(new Employee(1010, "Rajeev", 100000.00, LocalDate.of(2010, 7, 10)));
            employees.add(new Employee(1004, "Chris", 95000.50, LocalDate.of(2017, 3, 19)));
            employees.add(new Employee(1015, "David", 134000.00, LocalDate.of(2017, 9, 28)));
    
            System.out.println("Employees (Before Sorting) : " + employees);
    
            // This will use the `compareTo()` method of the `Employee` class to compare two employees and sort them.
            Collections.sort(employees);
    
            System.out.println("\nEmployees (After Sorting) : " + employees);
        }
    }
    
    # Output
    Employees (Before Sorting) : [Employee{id=1010, name='Rajeev', salary=100000.0, joiningDate=2010-07-10}, Employee{id=1004, name='Chris', salary=95000.5, joiningDate=2017-03-19}, Employee{id=1015, name='David', salary=134000.0, joiningDate=2017-09-28}]
    Employees (After Sorting) : [Employee{id=1004, name='Chris', salary=95000.5, joiningDate=2017-03-19}, Employee{id=1010, name='Rajeev', salary=100000.0, joiningDate=2010-07-10}, Employee{id=1015, name='David', salary=134000.0, joiningDate=2017-09-28}]
    

    任何实现Comparable接口的类都可以使用Sorted Sets和Sorted Maps开箱即用。

    Java Comparator

    Comparable我们在上一节中看到的接口定义了类对象的默认顺序。此默认排序也称为对象的自然排序

    但是,如果您只需要针对单个要求更改默认排序,该怎么办?例如,如果您想Employee根据名称而不是ID对上一个示例中的对象进行排序,该怎么办?

    您无法更改compareTo()函数的实现,因为它会影响到处的排序,而不仅仅是因为您的特定要求。

    此外,如果您正在处理预定义的Java类或第三方库中定义的类,您将无法更改默认顺序。例如,String对象的默认顺序是按字母顺序排序。但是如果你想根据它们的长度排序呢?

    对于这种情况,Java提供了一个Comparator接口。您可以定义一个Comparator并将其传递给排序函数,Collections.sort或者Arrays.sort根据由此定义的排序对对象进行排序Comparator

    Comparator接口包含一个被调用的方法compare(),您需要实现该方法以定义类对象的顺序 -

    public interface Comparator<T> {
        int compare(T o1, T o2);
    }
    

    compare()方法的实现应该返回

    • 一个负整数,如果第一个参数小于第二个参数,
    • 如果第一个参数等于第二个参数,则为零
    • 如果第一个参数大于第二个参数,则为正整数。

    让我们看一个让事情变得清晰的例子。

    Java Comparator接口示例

    让我们看看如何Employee通过定义不同的方法,根据不同的字段对我们在上一节中定义的对象集合进行排序Comparators

    import java.time.LocalDate;
    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<Employee> employees = new ArrayList<>();
    
            employees.add(new Employee(1010, "Rajeev", 100000.00, LocalDate.of(2010, 7, 10)));
            employees.add(new Employee(1004, "Chris", 95000.50, LocalDate.of(2017, 3, 19)));
            employees.add(new Employee(1015, "David", 134000.00, LocalDate.of(2017, 9, 28)));
            employees.add(new Employee(1009, "Steve", 100000.00, LocalDate.of(2016, 5, 18)));
    
            System.out.println("Employees : " + employees);
    
            // Sort employees by Name
            Comparator<Employee> employeeNameComparator = new Comparator<Employee>() {
                @Override
                public int compare(Employee e1, Employee e2) {
                    return e1.getName().compareTo(e2.getName());
                }
            };
    
            /*
            The above Comparator can also be written using lambda expression like so =>
            employeeNameComparator = (e1, e2) -> e1.getName().compareTo(e2.getName());
    
            Which can be shortened even further using Java 8 Comparator default method
            employeeNameComparator = Comparator.comparing(Employee::getName)
            */
    
            Collections.sort(employees, employeeNameComparator);
            System.out.println("\nEmployees (Sorted by Name) : " + employees);
    
            // Sort employees by Salary
            Comparator<Employee> employeeSalaryComparator = new Comparator<Employee>() {
                @Override
                public int compare(Employee e1, Employee e2) {
                    if(e1.getSalary() < e2.getSalary()) {
                        return -1;
                    } else if (e1.getSalary() > e2.getSalary()) {
                        return 1;
                    } else {
                        return 0;
                    }
                }
            };
            
            Collections.sort(employees, employeeSalaryComparator);
            System.out.println("\nEmployees (Sorted by Salary) : " + employees);
    
            // Sort employees by JoiningDate
            Comparator<Employee> employeeJoiningDateComparator = new Comparator<Employee>() {
                @Override
                public int compare(Employee e1, Employee e2) {
                    return e1.getJoiningDate().compareTo(e2.getJoiningDate());
                }
            };
    
            Collections.sort(employees, employeeJoiningDateComparator);
            System.out.println("\nEmployees (Sorted by JoiningDate) : " + employees);
        }
    }
    
    # Output
    
    Employees : [Employee{id=1010, name='Rajeev', salary=100000.0, joiningDate=2010-07-10}, Employee{id=1004, name='Chris', salary=95000.5, joiningDate=2017-03-19}, Employee{id=1015, name='David', salary=134000.0, joiningDate=2017-09-28}, Employee{id=1009, name='Steve', salary=100000.0, joiningDate=2016-05-18}]
    Employees (Sorted by Name) : [Employee{id=1004, name='Chris', salary=95000.5, joiningDate=2017-03-19}, Employee{id=1015, name='David', salary=134000.0, joiningDate=2017-09-28}, Employee{id=1010, name='Rajeev', salary=100000.0, joiningDate=2010-07-10}, Employee{id=1009, name='Steve', salary=100000.0, joiningDate=2016-05-18}]
    Employees (Sorted by Salary) : [Employee{id=1004, name='Chris', salary=95000.5, joiningDate=2017-03-19}, Employee{id=1010, name='Rajeev', salary=100000.0, joiningDate=2010-07-10}, Employee{id=1009, name='Steve', salary=100000.0, joiningDate=2016-05-18}, Employee{id=1015, name='David', salary=134000.0, joiningDate=2017-09-28}]
    Employees (Sorted by JoiningDate) : [Employee{id=1010, name='Rajeev', salary=100000.0, joiningDate=2010-07-10}, Employee{id=1009, name='Steve', salary=100000.0, joiningDate=2016-05-18}, Employee{id=1004, name='Chris', salary=95000.5, joiningDate=2017-03-19}, Employee{id=1015, name='David', salary=134000.0, joiningDate=2017-09-28}]
    

    正如您在上面的示例中看到的,所有排序方法也接受Comparator接口的实例。它们使用Comparator接口compare()函数定义的排序来对对象进行排序。

    使用Java 8 Comparator的默认方法

    Comparator接口包含用于创建Comparator实例的各种默认工厂方法。

    Comparators通过使用这些工厂方法,我们在上一节中创建的所有内容都可以更加简洁。

    这是我们在上一节中使用Java 8 Comparator默认方法看到的相同的Comparator示例 -

    import java.time.LocalDate;
    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<Employee> employees = new ArrayList<>();
    
            employees.add(new Employee(1010, "Rajeev", 100000.00, LocalDate.of(2010, 7, 10)));
            employees.add(new Employee(1004, "Chris", 95000.50, LocalDate.of(2017, 3, 19)));
            employees.add(new Employee(1015, "David", 134000.00, LocalDate.of(2017, 9, 28)));
            employees.add(new Employee(1009, "Steve", 100000.00, LocalDate.of(2016, 5, 18)));
    
            System.out.println("Employees : " + employees);
    
            // Sort employees by Name
            Collections.sort(employees, Comparator.comparing(Employee::getName));
            System.out.println("\nEmployees (Sorted by Name) : " + employees);
    
            // Sort employees by Salary
            Collections.sort(employees, Comparator.comparingDouble(Employee::getSalary));
            System.out.println("\nEmployees (Sorted by Salary) : " + employees);
    
            // Sort employees by JoiningDate
            Collections.sort(employees, Comparator.comparing(Employee::getJoiningDate));
            System.out.println("\nEmployees (Sorted by JoiningDate) : " + employees);
    
            // Sort employees by Name in descending order
            Collections.sort(employees, Comparator.comparing(Employee::getName).reversed());
            System.out.println("\nEmployees (Sorted by Name in descending order) : " + employees);
    
            // Chaining multiple Comparators
            // Sort by Salary. If Salary is same then sort by Name
            Collections.sort(employees, Comparator.comparingDouble(Employee::getSalary).thenComparing(Employee::getName));
            System.out.println("\nEmployees (Sorted by Salary and Name) : " + employees);
        }
    }
    
    # Output
    
    Employees : [Employee{id=1010, name='Rajeev', salary=100000.0, joiningDate=2010-07-10}, Employee{id=1004, name='Chris', salary=95000.5, joiningDate=2017-03-19}, Employee{id=1015, name='David', salary=134000.0, joiningDate=2017-09-28}, Employee{id=1009, name='Steve', salary=100000.0, joiningDate=2016-05-18}]
    Employees (Sorted by Name) : [Employee{id=1004, name='Chris', salary=95000.5, joiningDate=2017-03-19}, Employee{id=1015, name='David', salary=134000.0, joiningDate=2017-09-28}, Employee{id=1010, name='Rajeev', salary=100000.0, joiningDate=2010-07-10}, Employee{id=1009, name='Steve', salary=100000.0, joiningDate=2016-05-18}]
    Employees (Sorted by Salary) : [Employee{id=1004, name='Chris', salary=95000.5, joiningDate=2017-03-19}, Employee{id=1010, name='Rajeev', salary=100000.0, joiningDate=2010-07-10}, Employee{id=1009, name='Steve', salary=100000.0, joiningDate=2016-05-18}, Employee{id=1015, name='David', salary=134000.0, joiningDate=2017-09-28}]
    Employees (Sorted by JoiningDate) : [Employee{id=1010, name='Rajeev', salary=100000.0, joiningDate=2010-07-10}, Employee{id=1009, name='Steve', salary=100000.0, joiningDate=2016-05-18}, Employee{id=1004, name='Chris', salary=95000.5, joiningDate=2017-03-19}, Employee{id=1015, name='David', salary=134000.0, joiningDate=2017-09-28}]
    Employees (Sorted by Name in descending order) : [Employee{id=1009, name='Steve', salary=100000.0, joiningDate=2016-05-18}, Employee{id=1010, name='Rajeev', salary=100000.0, joiningDate=2010-07-10}, Employee{id=1015, name='David', salary=134000.0, joiningDate=2017-09-28}, Employee{id=1004, name='Chris', salary=95000.5, joiningDate=2017-03-19}]
    Employees (Sorted by Salary and Name) : [Employee{id=1004, name='Chris', salary=95000.5, joiningDate=2017-03-19}, Employee{id=1010, name='Rajeev', salary=100000.0, joiningDate=2010-07-10}, Employee{id=1009, name='Steve', salary=100000.0, joiningDate=2016-05-18}, Employee{id=1015, name='David', salary=134000.0, joiningDate=2017-09-28}]
    

    结论

    在本文中,您了解了Java的Comparable和Comparator接口。我们首先理解这些接口,然后查看各种示例以了解如何在实践中使用它们。

    我希望这篇文章对你有用。

    相关文章

      网友评论

          本文标题:Java Comparable和Comparator接口

          本文链接:https://www.haomeiwen.com/subject/cqwwjctx.html