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.
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ệnComparator<Employee>và phương thứccompare()của giao diện. DùngDouble.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 khaiComparator<Employee>và dùng phương thứccompareTo()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,salaryTạo một
ArrayListchứa nhân viên, sau đó minh họa cả hai cách sắp xếp:- Trước tiên, sắp xếp theo mức lương bằng
SalaryComparatorcủa bạn và in ra từng nhân viên - In ra một dòng trống
- Sau đó, sắp xếp theo tên bằng
NameComparatorcủa bạn và in ra từng nhân viên
- Trước tiên, sắp xếp theo mức lương bằng
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
}
}
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
1Kiến thức cơ bản về lập trình hướng đối tượng
Tệp bên ngoàiGiới thiệu về lập trình hướng đối tượngLớp và đối tượngTừ khóa thisPhương thứcTrường (thuộc tính)Phương thức khởi tạoNạp chồng phương thức khởi tạoÔn tập: Máy tính đơn giản4Kế thừa
Kế thừa cơ bản (extends)Từ khóa superGhi đè phương thức (@Override)Chuỗi gọi hàm khởi tạoLớp ObjectKế thừa đơn và đa cấpVì sao không hỗ trợ kế thừa nhiều lớpÔn tập: Phân cấp lớp Employee7Phương thức đặc biệt và lớp Object
Phương thức toString()equals() và hashCode()Phương thức clone()compareTo() và ComparableGiao diện ComparatorÔn tập: sắp xếp tùy chỉnh2Bộ điều chỉnh quyền truy cập và đóng gói
Tổng quan về các mức truy cậpPhương thức getter và setterẨn thông tinTừ khóa finalÔn tập: Trình quản lý tài khoản ngân hàng5Tính đa hình
Kiến thức cơ bản về nạp chồng phương thứcGhi đè phương thức (thời gian chạy)Chuyển kiểu lên và chuyển kiểu xuốngToán tử instanceofLớp và phương thức trừu tượngÔn tập: máy tính hình học8Khái niệm OOP nâng cao
Kết hợp và kế thừaKết tập và hợp thànhLớp bên trong, lớp lồng nhau và lớp ẩn danhKiểu enum và phương thức enumBản ghi (Java 16+)Lớp sealed (Java 17+)3Thuộc tính lớp và thành viên tĩnh
Biến của instance và biến tĩnhPhương thức tĩnhKhối tĩnhHằng số (static final)Ôn tập: bộ đếm và tiện ích6Giao diện và lớp trừu tượng
Giới thiệu về giao diệnTriển khai giao diệnTriển khai nhiều giao diệnPhương thức mặc định và tĩnh trong giao diệnLớp trừu tượng và giao diệnGiao diện hàmÔn tập: hệ thống thanh toán9Kiểu tổng quát
Giới thiệu về kiểu tổng quátLớp tổng quátPhương thức tổng quátTham số kiểu có giới hạnKý tự đại diện (?, extends, super)Ôn tập: vùng chứa tổng quát12Mẫu thiết kế, phần 2
Mẫu CommandMẫu AdapterMẫu DecoratorMẫu Template MethodMẫu StateMẫu CompositeMẫu IteratorTự luyện tập: Trình biên dịch Java online