Trong SQL thì câu lệnh GROUP BY dùng để trả về một tập hợp các records giống nhau ở một tiêu chí nào đó. Ví dụ bạn có một table có chứa thông tin sinh viên, mỗi sinh viên đến từ một quốc gia khác nhau. Sử dụng câu lệnh GROUP BY theo tiêu chí quốc gia, các bạn có thể biết số sinh viên đến từ quốc gia nào đó. Tương tự như vậy từ Java 8, Java cũng hỗ trợ cho chúng ta chức năng group by. Trong bài viết này, mình sẽ hướng dẫn các bạn làm cách nào để group by sử dụng Stream và Collectors trong Java các bạn nhé!
Ví dụ, mình có danh sách sinh viên với các thông tin như sau:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 |
package com.huongdanjava.javaexample; public class Student { private String name; private String country; public Student(String name, String country) { this.name = name; this.country = country; } public String getName() { return name; } public void setName(String name) { this.name = name; } public String getCountry() { return country; } public void setCountry(String country) { this.country = country; } @Override public int hashCode() { final int prime = 31; int result = 1; result = prime * result + ((country == null) ? 0 : country.hashCode()); result = prime * result + ((name == null) ? 0 : name.hashCode()); return result; } @Override public boolean equals(Object obj) { if (this == obj) return true; if (obj == null) return false; if (getClass() != obj.getClass()) return false; Student other = (Student) obj; if (country == null) { if (other.country != null) return false; } else if (!country.equals(other.country)) return false; if (name == null) { if (other.name != null) return false; } else if (!name.equals(other.name)) return false; return true; } @Override public String toString() { return "Student{" + "name='" + name + '\'' + ", country='" + country + '\'' + '}'; } } |
1 2 3 4 5 |
List<Student> names = Arrays.asList( new Student("Khanh", "VN"), new Student("Peter", "US"), new Student("Thanh", "VN"), new Student("Khanh", "VN")); |
Bây giờ, mình cần group danh sách sinh viên ở trên theo quốc gia và đếm số lượng sinh viên trong mỗi quốc gia.
Để làm được điều này, chúng ta sẽ sử dụng phương thức collect() trong đối tượng Stream cùng với phương thức static groupingBy() trong đối tượng Collectors của Java.
Ví dụ giờ chúng ta cần group danh sách sinh viên theo quốc gia thì chúng ta sẽ code như sau:
1 2 |
Map<String, List<Student>> result = names.stream() .collect(Collectors.groupingBy(Student::getCountry)); |
Kết quả:
Trong đoạn code trên, tham số của phương thức groupingBy() sẽ là tiêu chí mà chúng ta sẽ group giống như trong SQL. Nếu các bạn muốn group theo tên sinh viên thì có thể thay thế Student::getCountry bằng Student::getName.
Như các bạn thấy, mặc định thì sau khi group xong, những phần tử nào có cùng tiêu chí sẽ nằm trong một List object, chúng ta có thể thay đổi điều này bằng cách truyền thêm một tham số nữa vào phương thức groupingBy() của đối tượng Collectors. Ví dụ như, giờ mình muốn những phần tử nào có cùng tiêu chí sẽ nằm trong một Set object thì mình sẽ code như sau:
1 2 |
Map<String, Set<Student>> result = names.stream() .collect(Collectors.groupingBy(Student::getCountry, Collectors.toSet())); |
Kết quả:
Thêm nữa, nếu sau khi group xong, các bạn muốn đếm số lượng sinh viên của mỗi quốc gia thì hãy sẽ sử dụng phương thức groupingBy như sau:
1 2 |
Map<String, Long> result = names.stream() .collect(Collectors.groupingBy(Student::getCountry, Collectors.counting())); |
Ở đây, mình đã sử dụng thêm một phương thức khác của đối tượng Collectors tên là counting() để đếm số lượng sinh viên theo mỗi quốc gia mà mình muốn.
Kết quả:
Nam Tran
Hay