Menu
CoddyTech

Giao diện Comparator

Thuộc phần Lập trình hướng đối tượng trong hành trình Java của Coddy. Bài học 45 trên 87.

Mặc dù Comparable xác định thứ tự tự nhiên của một lớp, đôi khi bạn cần sắp xếp các đối tượng theo nhiều cách khác nhau. Giao diện Comparator cho phép bạn tạo logic so sánh riêng mà không cần sửa đổi lớp ban đầu.

Comparator là một đối tượng bên ngoài dùng để so sánh hai đối tượng cùng kiểu. Điều này hữu ích khi bạn muốn có nhiều tùy chọn sắp xếp hoặc khi bạn không thể chỉnh sửa chính lớp đó:

import java.util.Comparator;

class NameComparator implements Comparator<Person> {
    @Override
    public int compare(Person p1, Person p2) {
        return p1.getName().compareTo(p2.getName());
    }
}

class AgeComparator implements Comparator<Person> {
    @Override
    public int compare(Person p1, Person p2) {
        return p1.getAge() - p2.getAge();
    }
}

Sau đó, bạn có thể truyền bộ so sánh vào các phương thức sắp xếp:

List<Person> people = new ArrayList<>();
people.add(new Person("Charlie", 30));
people.add(new Person("Alice", 25));

Collections.sort(people, new NameComparator());  // Sắp xếp theo tên
Collections.sort(people, new AgeComparator());   // Sắp xếp theo tuổi

Để viết code ngắn gọn, bạn có thể dùng biểu thức lambda vì Comparator là một giao diện hàm:

Collections.sort(people, (p1, p2) -> p1.getName().compareTo(p2.getName()));

Điểm khác biệt chính: lớp được so sánh triển khai Comparable và xác định một thứ tự tự nhiên, còn Comparator là một lớp riêng có thể xác định không giới hạn thứ tự tùy chỉnh.

challenge icon

Thử thách

Dễ

Hãy xây dựng một hệ thống sắp xếp nhân viên để thể hiện sức mạnh của giao diện Comparator. Bạn sẽ tạo nhiều bộ so sánh để sắp xếp nhân viên theo những cách khác nhau, theo mức lương và theo tên, mà không cần sửa đổi lớp Employee.

Bạn sẽ tổ chức code trong bốn tệp:

  • Employee.java: Tạo một lớp đại diện cho nhân viên với ba trường private: name (String), department (String) và salary (double). Thêm hàm khởi tạo để khởi tạo tất cả các trường và các phương thức getter cho từng trường. Ghi đè toString() để trả về: [name] ([department]) - $[salary]
  • SalaryComparator.java: Tạo một bộ so sánh sắp xếp nhân viên theo mức lương theo thứ tự giảm dần (người có lương cao nhất đứng đầu). Triển khai giao diện Comparator<Employee> và phương thức compare() của giao diện. Dùng Double.compare() để so sánh giá trị lương một cách an toàn.
  • NameComparator.java: Tạo một bộ so sánh khác để sắp xếp nhân viên theo tên theo thứ tự bảng chữ cái, theo thứ tự tăng dần (từ A đến Z). Triển khai Comparator<Employee> và dùng phương thức compareTo() của String để so sánh.
  • Main.java: Kết hợp mọi thứ bằng cách tạo danh sách nhân viên và sắp xếp danh sách bằng các bộ so sánh của bạn. Bạn sẽ nhận đầu vào của ba nhân viên, mỗi người trên một dòng riêng theo định dạng: name,department,salary

    Tạo một ArrayList chứa nhân viên, sau đó minh họa cả hai cách sắp xếp:

    1. Trước tiên, sắp xếp theo mức lương bằng SalaryComparator của bạn và in ra từng nhân viên
    2. In ra một dòng trống
    3. Sau đó, sắp xếp theo tên bằng NameComparator của bạn và in ra từng nhân viên

Bạn sẽ nhận ba dòng đầu vào, mỗi dòng chứa dữ liệu nhân viên theo định dạng: name,department,salary

Ví dụ, một dòng đầu vào có thể như sau: Alice,Engineering,75000.0

Nhớ import java.util.Comparator trong các tệp bộ so sánh, và java.util.ArrayList, java.util.Collections cùng java.util.Scanner trong tệp Main. Bạn sẽ thấy các bộ so sánh cho phép xác định nhiều cách sắp xếp từ bên ngoài: lớp Employee không cần biết gì về cách nó có thể được sắp xếp!

Tự làm thử

import java.util.ArrayList;
import java.util.Collections;
import java.util.Scanner;

class Main {
    public static void main(String[] args) {
        Scanner scanner = new Scanner(System.in);
        
        // Đọc thông tin của ba nhân viên từ đầu vào
        // Định dạng mỗi dòng: name,department,salary
        String line1 = scanner.nextLine();
        String line2 = scanner.nextLine();
        String line3 = scanner.nextLine();
        
        // TODO: Phân tích từng dòng và tạo các đối tượng Employee
        // Gợi ý: Dùng split(",") để tách các giá trị
        
        // TODO: Tạo một ArrayList chứa nhân viên và thêm cả ba người
        
        // TODO: Sắp xếp theo lương bằng SalaryComparator và in ra từng nhân viên
        // Gợi ý: Dùng Collections.sort(list, comparator)
        
        // TODO: In ra một dòng trống
        
        // TODO: Sắp xếp theo tên bằng NameComparator và in ra từng nhân viên
    }
}
quiz iconTự kiểm tra

Bài học này có một bài trắc nghiệm ngắn. Bắt đầu bài học để trả lời và theo dõi tiến độ.

Tất cả bài học trong Lập trình hướng đối tượng

Tự luyện tập: Trình biên dịch Java online