Java Stream – Collectors và Statistics
Bài viết được sự cho phép của tác giả Kiên Nguyễn
Làm việc với Stream Collector/ Collectors đã lâu, liệu rằng bạn có biết ngoài Grouping và Partitioning, Stream còn hỗ trợ cả thống kê (Statistics). Bất ngờ chưa, Collector thật sự còn ẩn chứa nhiều điều mà anh em còn chưa biết tới.
Hãy cùng tìm hiểu collector và các methods của nó qua bài viết dưới đây. Cuộc đời anh em developer chúng ta sẽ bớt khổ.
Xem thêm các Việc làm Java hấp dẫn trên TopDev
Trường hợp muốn tìm hiểu sâu hơn về stream và stream how it’s works, các bạn có thể khảo bài viết này.
1. Collectors.
A Collector represents a way to combine the elements of a Stream into one result.
Collector đại diện cho cách kết hợp tất cả các đối tượng trong Stream thành một kết quả duy nhất.
Để hoàn thành nhiệm vụ của mình, collectors sẽ chịu trách nhiệm thực thi 3 nhóm tác vụ chính:
- A supplier of an initial value. Cung cấp một giá trị ban đầu.
- An accumulator which adds to the initial value. – Nơi tổng hợp một loạt các giá trị ban đầu.
- A combiner which combines two results into one. – Kết hợp hai kết quả thành một.
Collector được sử dụng thường xuyên khi ta sử dụng Stream API, nhưng ta ít khi để ý tới. Có hai cách để sử dụng:
// Phương thức ngắn gọn. collect(Collector) (types left off for brevity)
// Các phương thức chi tiết để có một collection. collect(supplier,accumulator,combiner).
Phương thức import để sử dụng collectors là:
import staticjava.util.stream.Collectors.*;
1.1 Collectors đơn giản.
Hai methods đơn giản và thường được sử dụng nhiều với collectors là toList() và toCollection().
// Lấy danh sách tên toàn bộ gái xinh, chuyển qua List. List<String> listGaiXinh = Gai.stream() .map(Gai::getName) .collect(toList()); // Lấy danh sách tên toàn bộ gái xinh, chuyển qua TreeSet. Set<String> setGaiXinh = Gai.stream() .map(Gai::getName) .collect(toCollection(TreeSet::new));
1.2 Joinning.
Trước đây, muốn Joining chuỗi trong Java, thường ta sử dụng Apache Common StringUtils.join. Khi sử dụng collector, ta có thể gọi phương thức joining. Khi gọi phương thức này, bản thân collectors lúc này biến thành một thùng chứa, kết nối các chuỗi String nhỏ, cho ra một String lớn.
// Tạo chuỗi gái xinh, cách nhau bởi dấu phẩy. gaiXinhStr = gai.stream() .map(Gai::getName) .collect(joining(","));
2. Statistics.
Ngoài công việc kết nối hoặc tổng hợp một loạt các giá trị. Collector còn cung thêm cả chức năng thống kê (statistics).
// Đọc file Rio, tính trung bình các dòng khác rỗng. System.out.println( Files.lines(Paths.get("Rio.java")) .map(String::trim) .filter(s -> !s.isEmpty()) .collect(averagingInt(String::length)) );
2.1 Summarizing.
Summarizing là một method của collector, phương thức này trả về một lớp đặc biệt chứa thông tin thống kê (statistical information). Thông tin này thống kê dữ liệu cuối đã được trích xuất khỏi Stream.
// Lấy danh sách gái xinh có số đo vòng một cực lớn. // Ôi, tao thích Collectos quá đi thôi. =))) int soEmVongMotLon = gaiXinh.stream() .collect(summarizingInt(Gai::vongMotLon));
2.2 Averaging.
Phương thức averaging trả về giá trị trung bình của các đối tượng.
// Tính tuổi trung bình danh sách gái xinh. // Có collectors, đã không còn cực như xưa. int tuoiTrungBinh = gaiXinh.stream() .collect(averagingInt(Gai::getAge));
2.3 Summing.
Tương tự như tính giá trị trung bình, Summing trả về tổng các đối tượng trong Stream.
// Tính tổng số tuổi danh sách gái xinh. // Có collectors, đã không còn cực như xưa. int tongSoTuoi = gaiXinh.stream() .collect(SummingInt(Gai::getAge));
2.4 MaxBy / MinBy.
MaxBy/MinBy collectors return the biggest/the smallest element of a Stream according to a provided Comparator instance.
MaxBy/MinBy collectors trả về giá trị lớn nhất/ nhỏ nhất của Stream theo thể hiện được cung cấp bởi Comparator.
// Lấy // Có collectors, đã không còn cực như xưa. Optional<String> result = gaiXinh.stream() .collect(maxBy(Comparator.getAge()));
Có một lưu ý nhỏ là giá trị trả về khi gọi phương thức MaxBy và MinBy phải được đóng gói theo kiểu Optional instance.
2.5 Grouping By.
GroupingBy collector is used for grouping objects by some property and storing results in a Map instance.
GroupingBy collector được sử dụng để gom một số đối tượng bởi thuộc tính của chúng, kết quả trả về sẽ được lưu vào một thể hiện (instance) của Map.
Map<Integer, Set<String>> result = givenList.stream() .collect(groupingBy(String::length, toSet()));
2.6 Partitioning By.
PartitioningBy is a specialized case of groupingBy that accepts a Predicate instance and collects Stream elements into a Map instance that stores Boolean values as keys and collections as values.
PartitioningBy là một trường hợp đặc biệt của groupingBy, nó chấp nhận thêm Predicate Instance và Stream elements bên trong Map, các giá trị này sẽ được lưu kiểu Boolean giống như một keys.
Lý thuyết như thế này thì hơi khó hiểu. Ví dụ như sau: Nếu bạn có một nhóm bạn năm người. Trong đó, ba người ăn chay, hai người còn lại thì không. Ta sẽ sử dụng partitioning để chia nhóm người thành 2 vùng (ăn chay và không).
Hai nhóm người được phân như sau:
- Ăn chay: Hạnh, Hải, Anh, Ẩn.
- Ăn mặn: Hậu, Vinh, Tú, Tùng.
Map<Boolean, List<Dish>> partitionedMenu = menu.stream() .collect(partitioningBy(Dish::isVetetarian));
Kết quả trả về sẽ là:
- True: [Hạnh, Hải, Anh, Ẩn].
- False: [Hậu, Vinh, Tú, Tùng].
Chỉ nên sử dụng partitioningBy trong trường hợp phép so sánh để phân các đối tượng thành vùng là phức tạp. Ngược lại, đơn giản ta chỉ cần sử dụng Stream.filter().
List<Dish> vegetarianDishes = menu.stream() .filter(Dish::isVegetarian) .collect(toList());
3. Kết luận.
Stream và Collectors kết hợp lại với nhau thật sự là một cặp đôi song sát. Hữu hiệu và mạnh mẽ. Việc ghi nhớ các method được cung cấp bởi Collector sẽ rất hữu hiệu cho anh em trong quá trình code. Sử dụng linh hoạt collector giúp code trở nên đơn giản, dễ đọc, dễ mantainance.
Ngoài ra, collectors còn trở nên mạnh mẽ hơn khi ta có thể custom một class của nó, tạo riêng cho mình một collector.
Mong rằng bài viết này sẽ giúp đỡ các bạn phần nào.
Thanks and love u so much!.
4. Tham khảo.
Bài viết gốc được đăng tải tại kieblog.vn
Có thể bạn quan tâm:
- Streaming Media với Nginx và nginx-rtmp module
- Java map và flatmap – điều gì làm nên khác biệt?
- Loại bỏ các phần tử trùng trong một ArrayList như thế nào trong Java 8?
Xem thêm Việc làm IT hấp dẫn trên TopDev
- B BenQ RD Series – Dòng Màn Hình Lập Trình 4k+ Đầu Tiên Trên Thế Giới
- i iOS 18 có gì mới? Có nên cập nhật iOS 18 cho iPhone của bạn?
- G Gamma AI là gì? Cách tạo slide chuyên nghiệp chỉ trong vài phút
- P Power BI là gì? Vì sao doanh nghiệp nên sử dụng PBI?
- K KICC HCMC x TOPDEV – Bước đệm nâng tầm sự nghiệp cho nhân tài IT Việt Nam
- T Trello là gì? Cách sử dụng Trello để quản lý công việc
- T TOP 10 SỰ KIỆN CÔNG NGHỆ THƯỜNG NIÊN KHÔNG NÊN BỎ LỠ
- T Tìm hiểu Laptop AI – So sánh Laptop AI với Laptop thường
- M MySQL vs MS SQL Server: Phân biệt hai RDBMS phổ biến nhất
- S SearchGPT là gì? Công cụ tìm kiếm mới có thể đánh bại Google?