So sánh 2 tiêu chí comparator trong java năm 2024

*Lưu ý: vì post này được viết dựa trên kiến thức cá nhân nên có thể có sai sót, rất mong những ý kiến, đóng góp từ mọi người. .

1. Lời dạo đầu

Chắc các bạn cũng đã biết API Collections rồi (chưa biết cũng chả sao). Đây là class giúp lập trình viên thao tác đủ thứ: sort phần tử, sắp xếp random phần tử, cho biết số lần xuất hiện của 1 phần tử,…với các collection: ArrayList, Vector, LinkedList,…Hôm nay mình chỉ nói đến chức năng sort của Collections.

Để mở đầu câu chuyện, xin mọi người thưởng thức source code dùng Collections để sort ArrayList có các phần tử kiểu String:

import java.util.ArrayList; import java.util.Collections; / *

  • @author Huynh Tinh */ public class TestComparasion {
    public static void main(String[] args) {
        // TODO code application logic here
        // tạo 3 mảng và add vào ArrayList rồi sort
        String hello = "hello";
        String tynk = "tynk";
        String java = "java";
        ArrayList array = new ArrayList();
        array.add(tynk);
        array.add(java);
        Collections.sort(array);
        System.out.println(array);
    }
    
    }

Output: [hello, java, tynk]

Lưu ý: Collections không làm việc với các mảng thông thường như int[], float[]. String[],…

Vậy còn Class mà mình tự tạo thì sao ??

Đầu tiên cứ tạo ra môt class đã rồi cứ sort xem sao:

import java.util.ArrayList; import java.util.Collections; // tao class Student public class Student {

 String name;
 int age;
 int grade;
 public Student(String name, int age, int grade) {
     this.name = name;
     this.age = age;
     this.grade = grade;
 }
 public String getName() {
     return name;
 }
 public void setName(String name) {
     this.name = name;
 }
 public int getAge() {
     return age;
 }
 public void setAge(int age) {
     this.age = age;
 } 
 public int getGrade() {
     return grade;
 } 
 public void setGrade(int grade) {
     this.grade = grade;
 }
// test sort Student
 public static void main(String[] args) {
     Student tynk = new Student("tynk", 19, 12);
     Student java = new Student("java", 10, 5);
     ArrayList arrayList = new ArrayList();
     students.add(tynk);
     students.add(java);
     Collections.sort(arrayList);
     System.out.println(arrayList);
 }
}

Output: Exception in thread “main” java.lang.RuntimeException: Uncompilable source code – Erroneous sym type: java.util.Collections.sort

Có gì hot ??? Tại sao ta có thể sort kiểu phần tử kiểu String được nhưng Student thì không ? Hay có sự khác biệt gì giữa String vs Student ?? Chúng ta hãy xem cấu trúc phương thức của sort của Collection:

static Comparable> void (List list)

T: dùng để ám chỉ kiểu dữ liệu của object bất kì, ở ví dụ này T là Student

Nói tóm gọn: để thực hiện phương thức sort này, Collections yêu cầu ArrayList implement List (đã duyệt). Nhưng đó là chưa đủ, các phần tử Student của ArrayList phải implement interface Comparable.

Wow !!! Đúng là Student chưa thông thạo bí kíp Comparable thật. Nếu bạn có tìm hiểu thì kiểu String đã implement interface này sẵn rồi. Vậy interface Comparable dùng để làm gì ???

Bạn muốn tìm hiểu Collections: https://docs.oracle.com/javase/7/docs/api/java/util/Collections.html

2. Comparable:

Khi một class implement interface Comparable, Collections dựa vào đó mà biết cách sắp xếp các phần tử có kiểu class đó như thế nào. Nhưng cụ thể dựa vào cái gì ???

Khi implement Comparable cho 1 class, bắt buộc ta phải override lại phương thức compareTo(T o) cho class đó, phương thức này như là tiêu chuẩn mà Collections dựa vào mà sort các phần tử vào vị trí thích hợp. Khi gọi phương thức sort(List list) từ Collections, Collections sẽ lần lượt gọi phương thức compareTo(T o) của từng phần tử để so sánh phần tử này với phần tử khác và dựa vào giá trị trả về mà sort chúng.

Vậy ta viết gì trong phương thức compareTo ??? Tùy vào bạn muốn so sánh các phần tử dụa vào tiêu chuẩn gì, đa số là dựa vào giá trị của biến instance của chúng. Quay lại ví dụ, bây giờ mình muốn sort các Student theo tên. Dưới đây là source code :

import java.util.ArrayList; import java.util.Collections; / *

  • @author Huynh Tinh */ // tao class Student + implement Comparable public class Student implements Comparable {
    String name;
    int age;
    int grade;
    public Student(String name, int age, int grade) {
        this.name = name;
        this.age = age;
        this.grade = grade;
    }
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    public int getAge() {
        return age;
    }
    public void setAge(int age) {
        this.age = age;
    }
    public int getGrade() {
        return grade;
    }
    public void setGrade(int grade) {
        this.grade = grade;
    } 
    // Override phuong thuc, so sanh dua theo ten
     @Override
     public int compareTo(Student student) {
         return this.getName().compareTo(student.getName());
     }
    // tra ve tên cua phan tu
    @Override
    public String toString() {
         return this.name;
    }
    public static void main(String[] args) {
         Student tynk = new Student("tynk", 19, 12);
         Student java = new Student("java", 10, 5);
         ArrayList arrayList = new ArrayList();
         arrayList.add(tynk);
         arrayList.add(java);
         Collections.sort(arrayList);
         System.out.println(arrayList);
    }
    
    }

Output: [java, tynk]

Olala !!! Vậy đã sort theo tên thành công !!! Nhưng có 1 câu hỏi: vậy cần quái gì interface Comparator ??

Lưu ý:

  • Bởi vì phương thức compareTo() trả về kiểu int nên có 1 quy ước:
    • trả về giá trị âm: phần tử hiện tại < phần tử khác
    • trả về 0: phần tử hiện tại = phần tử khác
    • trả về giá trị dương: phần tử hiện tại > phần tử khác
  • Các bạn có thể dựa theo quy ước trên để điều chỉnh phương thức comparaTo() phù hợp cho riêng bạn

Bạn muốn tìm hiểu về Comparable: https://docs.oracle.com/javase/8/docs/api/java/lang/Comparable.html

2. Comparator

Giả sử ngoài sort Student theo tên, bây giờ chúng ta muốn sort theo tuổi (age) hay theo khối lớp (grade) thì làm thế nào nhỉ ?? Override thêm phương thức compareTo ??? Không được nhé: 1 class chỉ được override 1 phương thức duy nhất 1 lần. Chỉnh sửa lại phương thức ??? Được nhưng giả sử trong chương trình sẽ có lúc sort theo tên nhưng sẽ có lúc sort theo tuổi thì sao ???

Đau đầu quá !!!

Interface Comparator chính là cách giải quyết vấn đề trên, tuy nhiên interface này sẽ không đi với phương thức sort(List list) mà là:

static void (List list, Comparator c)

Nghĩa là Collections hỗ trợ đến 2 phương thức sort, thật tuyệt vời phải không nào ??

Ở phương thức này, Collections không yêu cầu các phần tử trong list phải implement Comparable mà thay vi đó, phải truyền thêm vào 1 biến tham chiếu của object kiểu class có implement Comparator.

Ngoài ra, khi implement Comparator thì bạn phải override lại phương thức compare(T o1, T o2), cũng trả về kiểu int, và quy ước thì không khác gì với CompartTo(T o) của Comparable: trả về giá trị âm nếu o1 < o2,….Điều cần nhớ là Collections sẽ gọi phương thức này để biết cách sort phần tử.

Dĩ nhiên ta sẽ tạo thêm 2 class implement Comparator, nhưng hôm nay mình xin làm 1 class để sort theo tuổi, class còn lại các bạn có thể tự làm như một phần bài tập.

Dưới đây là sourcecode của AgeComparator:

import java.util.Comparator; / *

  • @author Huynh Tinh */ // class implement Comparator dung de sort Student theo tuoi public class AgeComparator implements Comparator {
    @Override
    public int compare(Student o1, Student o2) {
        if (o1.getAge() < o2.getAge()) {
            return -1;
        } else if (o1.getAge() == o2.getAge()) {
            return 0;
        } else {
            return 1;
        }
    }
    
    }

Và source code của Student

import java.util.ArrayList; import java.util.Collections; / *

  • @author Huynh Tinh */ public class Student implements Comparable {
    String name;
    int age;
    int grade;
    public Student(String name, int age, int grade) {
        this.name = name;
        this.age = age;
        this.grade = grade;
    }
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    public int getAge() {
        return age;
    }
    public void setAge(int age) {
        this.age = age;
    }
    public int getGrade() {
        return grade;
    }
    public void setGrade(int grade) {
        this.grade = grade;
    }
    // tra ve ten + tuoi
    @Override
    public String toString() {
        return this.name + " - " + age;
    }
    @Override
    public int compareTo(Student student) {
        return this.getName().compareTo(student.getName());
    } 
    public static void main(String[] args) {
        Student tynk = new Student("tynk", 19, 12);
        Student java = new Student("java", 10, 5);
        // them 1 student
        Student dnh = new Student("dnh", 26, 10);
        ArrayList arrayList = new ArrayList();
        arrayList.add(tynk);
        arrayList.add(java);
        arrayList.add(dnh);
        //sort theo ten
        Collections.sort(arrayList);
        System.out.println(arrayList);
        // sort theo tuoi
        // tao doi tuong AgeComparator
        AgeComparator ac = new AgeComparator();
        Collections.sort(arrayList, ac);
        System.out.println(arrayList);
     }
    
    }

Output:

[dnh – 26, java – 10, tynk – 19] // sort theo ten

[java – 10, tynk – 19, dnh – 26] // sort theo tuoi

Yayy !!! Vậy là ta đã sort được student theo tên, và sau đó là theo tuổi 1 cách dễ dàng rồi !!!

Bạn muốn tìm hiểu về Comparator: https://docs.oracle.com/javase/8/docs/api/java/lang/Comparable.html

4.Lời kết

Vậy là chúng ta đã phần nào đã biết được đôi chút về 2 interface này, hi vọng bài post sẽ giúp cho bạn. Đừng quên feedback, góp ý cho mình nhé, Hẹn gặp các bạn ở các bài post tiếp theo .