7c89d7e94a46148f - thể thao ngoại hạng anh

/imgposts/jteytxhd.jpg

Trong quá trình viết mã hàng ngày, chúng ta thường xuyên sử dụng Stream để xử lý các logic liên quan đến tập hợp. Các thao tác đơn giản như lấy giá trị hoặc lọc dữ liệu có thể dễ dàng hoàn thành nhờ sự hỗ trợ từ IDE. Tuy nhiên, có một số thao tác ít phổ biến hơn mà tôi muốn ghi lại ở đây, nhằm đảm bảo rằng mình sẽ tiếp tục cập nhật và bổ sung trong tương lai.

Stream trong Java cung cấp sẵn phương thức distinct để the thao 24h loại bỏ các phần tử trùng lặp. Tuy nhiên, phương thức này chỉ hoạt động khi bạn cần so sánh toàn bộ đối tượng. Ví dụ như đoạn mã dưới đây:

1public static void main(String[] args) {    
2    List<Integer> list = new ArrayList<>();    
3    list.add(1);    
4    list.add(1);    
5    list.add(2);    
6    list = list.stream().distinct().collect(Collectors.toList());    
7    System.out.println(list);  
8}

Kết quả sẽ là:

[1, 2]

Tuy nhiên, nếu phần tử của bạn là một đối tượng phức tạp và bạn muốn lọc dựa trên một thuộc tính cụ thể nào đó (ví dụ: userId), thì lúc này bạn cần áp dụng một phiên bản tùy chỉnh của distinct. Dưới đây là ví dụ minh họa khi bạn muốn loại bỏ trùng lặp dựa trên userId.

 1public static void main(String[] args) {    
 2    List<StudentRecord> list = new ArrayList<>();    
 3    StudentRecord s1 = new StudentRecord();    
 4    s1.setUserId(11L);    
 5    s1.setCourseId(100L);    
 6    s1.setScore(100);    
 7    list.add(s1);    
 8
 9    StudentRecord s2 = new StudentRecord();    
10    s2.setUserId(11L);    
11    s2.setCourseId(101L);    
12    s2.setScore(100);    
13    list.add(s2);    
14
15    StudentRecord s3 = new StudentRecord();    
16    s3.setUserId(12L);    
17    s3.setCourseId(100L);    
18    s3.setScore(100);    
19    list.add(s3);    
20
21    System.out.println(list.stream().distinct().collect(Collectors.toList()));  
22}  
23
24@Data  
25static class StudentRecord {    
26    Long id;    
27    Long userId;    
28    Long courseId;    
29    Integer score;  
30}

Kết quả sẽ là:

[StudentRecord(id=null, userId=11, courseId=100, score=100), 
 StudentRecord(id=null, userId=11, courseId=101, score=100), 
 StudentRecord(id=null, userId=12, courseId=100, score=100)]

Như vậy, mặc dù hai bóng đá anh đối tượng đều có cùng userId, nhưng vì chúng không được coi là giống nhau nên không bị loại bỏ. Để giải quyết vấn đề này, chúng ta cần tạo hàm distinctByKey tùy chỉnh như sau:

1public static <T> Predicate<T> distinctByKey(Function<? super T, ?> keyExtractor) {    
2    Map<Object, Boolean> seen = new ConcurrentHashMap<>();    
3    return t -> seen.putIfAbsent(keyExtractor.apply(t), Boolean.TRUE) == null;  
4}

Sau đó, bạn có thể sử dụng hàm này để lọc danh sách:

1System.out.println(
2    list.stream()
3        .filter(distinctByKey(StudentRecord::getUserId))
4        .collect(Collectors.toList())
5);

Kết quả cuối cùng sẽ là:

[StudentRecord(id=null, userId=11, courseId=100, score=100), 
 StudentRecord(id=null, userId=12, courseId=100, score=100)]

Thực tế mà nói, việc phải tự tạo hàm distinctByKey này có vẻ hơi thừa thãi, bởi lẽ nó đáng lẽ đã được tích hợp sẵn trong Stream API.