Java - Teeing Collectors

Xin chào các bạn, những phù thủy Java tương lai! ? Hôm nay, chúng ta sẽ bắt đầu hành trình thú vị vào thế giới của Teeing Collectors trong Java. Đừng lo nếu bạn mới bắt đầu học lập trình – tôi sẽ là người hướng dẫn bạn, và chúng ta sẽ làm theo từng bước. Khi hết hướng dẫn này, bạn sẽ ngạc nhiên về những gì bạn có thể làm với Java!

Java - Teeing Collectors

Teeing Collectors là gì?

Trước khi chúng ta nhảy vào sâu, hãy bắt đầu với những khái niệm cơ bản. Hãy tưởng tượng bạn đang ở một nhà hàng sang trọng, và phục vụ mang đến cho bạn một chảo trà với hai đầu. Đó là như thế nào Teeing Collector trong Java – nó là cách để bạn đổ dữ liệu vào hai "cốc" khác nhau (hoặc các thao tác) cùng một lúc!

Trong lingo Java, Teeing Collector cho phép bạn áp dụng hai collector độc lập vào cùng một đầu vào và sau đó kết hợp kết quả của chúng. Đó như có hai người giúp đỡ làm việc trên cùng một nhiệm vụ nhưng tập trung vào các khía cạnh khác nhau, và sau đó bạn kết hợp công việc của chúng lại vào cuối.

Phương thức Collectors.teeing()

Java giới thiệu phương thức Collectors.teeing() trong Java 12. Nó là một phần của API Stream, là một công cụ mạnh mẽ để xử lý các tập hợp dữ liệu. Hãy phân tích cú pháp của nó:

Cú pháp

public static <T,R1,R2,R> Collector<T,?,R> teeing(
Collector<? super T,?,R1> downstream1,
Collector<? super T,?,R2> downstream2,
BiFunction<? super R1,? super R2,R> merger)

Đừng để cú pháp này làm bạn sợ! Hãy phân tích nó:

  • T: Loại phần tử đầu vào
  • R1: Loại kết quả của collector đầu tiên
  • R2: Loại kết quả của collector thứ hai
  • R: Loại kết quả cuối cùng

Phương thức này nhận ba tham số:

  1. downstream1: Collector đầu tiên
  2. downstream2: Collector thứ hai
  3. merger: Hàm để kết hợp kết quả của hai collector

Bây giờ, hãy xem thử nó hoạt động với một số ví dụ!

Ví dụ 1: Tính trung bình và đếm số lượng

Hãy tưởng tượng bạn là một giáo viên (giống như tôi!) và bạn muốn tính điểm trung bình của học sinh của mình và đếm số lượng học sinh. Dưới đây là cách chúng ta có thể làm điều đó với Teeing Collector:

import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;

public class StudentScoreAnalyzer {
public static void main(String[] args) {
List<Integer> scores = Arrays.asList(85, 90, 78, 92, 88);

var result = scores.stream().collect(
Collectors.teeing(
Collectors.averagingInt(Integer::intValue),
Collectors.counting(),
(average, count) -> String.format("Trung bình: %.2f, Số lượng: %d", average, count)
)
);

System.out.println(result);
}
}

Hãy phân tích nó:

  1. Chúng ta bắt đầu với một danh sách điểm của học sinh.
  2. Chúng ta sử dụng scores.stream() để tạo một luồng của các điểm này.
  3. Chúng ta áp dụng Collectors.teeing() với hai collector:
  • Collectors.averagingInt(Integer::intValue) tính điểm trung bình.
  • Collectors.counting() đếm số lượng điểm.
  1. Hàm kết hợp kết quả này thành một chuỗi định dạng.

Khi chạy đoạn mã này, bạn sẽ thấy kết quả như sau:

Trung bình: 86.60, Số lượng: 5

Điều này có khá thú vị phải không? Chỉ với một vài dòng mã, chúng ta đã tính được hai chỉ số khác nhau từ dữ liệu của mình!

Ví dụ 2: Tìm điểm cao nhất và thấp nhất

Bây giờ, hãy tưởng tượng bạn muốn tìm cả điểm cao nhất và thấp nhất trong lớp của mình. Chúng ta có thể làm điều đó với một luồng duy nhất sử dụng Teeing Collector:

import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;

public class StudentScoreAnalyzer {
public static void main(String[] args) {
List<Integer> scores = Arrays.asList(85, 90, 78, 92, 88);

var result = scores.stream().collect(
Collectors.teeing(
Collectors.minBy(Integer::compareTo),
Collectors.maxBy(Integer::compareTo),
(min, max) -> String.format("Thấp nhất: %d, Cao nhất: %d", min.orElse(0), max.orElse(0))
)
);

System.out.println(result);
}
}

Trong ví dụ này:

  1. Chúng ta sử dụng cùng một danh sách điểm.
  2. Collector đầu tiên của chúng ta, Collectors.minBy(Integer::compareTo), tìm điểm thấp nhất.
  3. Collector thứ hai của chúng ta, Collectors.maxBy(Integer::compareTo), tìm điểm cao nhất.
  4. Hàm kết hợp kết quả này thành một chuỗi định dạng, sử dụng orElse(0) để xử lý trường hợp danh sách có thể trống.

Chạy đoạn mã này sẽ đưa ra kết quả:

Thấp nhất: 78, Cao nhất: 92

Tại sao sử dụng Teeing Collectors?

Bạn có thể hỏi, "Tại sao phải làm quá nhiều việc đó? Có thể chúng ta chỉ cần làm các thao tác này riêng biệt không?" Đúng là, bạn có thể làm như vậy! Nhưng Teeing Collectors mang lại một số lợi thế:

  1. Hiệu quả: Bạn chỉ cần duy trì một lần duyệt qua dữ liệu, điều này có thể làm tăng hiệu suất đối với các tập hợp dữ liệu lớn.
  2. Đọc dễ: Nó làm mã của bạn ngắn gọn và dễ hiểu ở một cái nhìn.
  3. Linhtẻ: Bạn có thể kết hợp bất kỳ hai collector nào theo cách sáng tạo để giải quyết các vấn đề phức tạp.

Ứng dụng thực tế

Teeing Collectors không chỉ dành cho các ví dụ đơn giản như trên. Chúng có thể rất hữu ích trong các tình huống thực tế:

  • Trong các ứng dụng tài chính, bạn có thể sử dụng chúng để tính tổng và trung bình của các giao dịch trong một lần duyệt.
  • Trong phân tích dữ liệu, bạn có thể sử dụng chúng để tìm cả trung vị và mô đề của một tập dữ liệu cùng lúc.
  • Trong phát triển game, bạn có thể theo dõi cả điểm cao nhất và số lượng người chơi đạt được điểm đó.

Kết luận

Và thế là, các bạn! Chúng ta đã leo thang vào thế giới của Teeing Collectors trong Java. Chúng ta đã thấy cách chúng có thể giúp chúng ta thực hiện hai thao tác cùng một lúc và kết hợp kết quả, tất cả đều trong một luồng hiệu quả.

Hãy nhớ, lập trình là việc giải quyết các vấn đề, và Teeing Collectors là chỉ một công cụ trong bộ công cụ giải quyết vấn đề của bạn. Khi bạn thực hành nhiều hơn với chúng, bạn sẽ tìm ra nhiều cách sáng tạo hơn để sử dụng chúng trong dự án của mình.

Hãy tiếp tục lập trình, học hỏi, và above all, have fun with it! Ai biết? Có lẽ một ngày nào đó bạn sẽ là người dạy Java, chia sẻ những trải nghiệm và câu chuyện hài của mình với một thế hệ mới của những người lập trình. Đến khi đó, chúc các bạn có một ngày lập trình vui vẻ! ??‍??‍?

Credits: Image by storyset