Hiểu Spliterator, Collector và Stream trong Java 8


143

Tôi gặp khó khăn khi hiểu Streamgiao diện trong Java 8, đặc biệt là nơi nó phải làm với giao diện SpliteratorCollector. Vấn đề của tôi là tôi chỉ đơn giản là không thể hiểu Spliteratorvà các Collectorgiao diện, và kết quả là Streamgiao diện vẫn còn hơi khó hiểu với tôi.

Chính xác thì a Spliteratorvà a là gì Collector, và làm thế nào tôi có thể sử dụng chúng? Nếu tôi sẵn sàng tự viết Spliteratorhoặc Collector(và có lẽ là của riêng tôi Streamtrong quá trình đó), tôi nên làm gì và không làm gì?

Tôi đọc một số ví dụ rải rác trên web, nhưng vì mọi thứ ở đây vẫn còn mới và có thể thay đổi, các ví dụ và hướng dẫn vẫn còn rất thưa thớt.

Câu trả lời:


142

Bạn gần như chắc chắn không bao giờ phải đối phó với Spliteratortư cách là người dùng; nó chỉ cần thiết nếu bạn tự viết Collectioncác loại và cũng có ý định tối ưu hóa các hoạt động song song trên chúng.

Đối với những gì đáng giá, đó Spliteratorlà cách vận hành các yếu tố của bộ sưu tập theo cách dễ dàng tách ra một phần của bộ sưu tập, ví dụ: vì bạn đang song song và muốn một luồng hoạt động trên một phần của bộ sưu tập, một chủ đề để làm việc trên một phần khác, vv

Về cơ bản, bạn cũng không bao giờ nên lưu các giá trị của loại Streamvào một biến. Streamgiống như một đối tượng Iterator, trong đó nó là một đối tượng sử dụng một lần mà hầu như bạn sẽ luôn sử dụng trong một chuỗi trôi chảy, như trong ví dụ Javadoc:

int sum = widgets.stream()
                  .filter(w -> w.getColor() == RED)
                  .mapToInt(w -> w.getWeight())
                  .sum();

Collectorlà phiên bản trừu tượng nhất, trừu tượng nhất có thể của thao tác "giảm" a la map / less; đặc biệt, nó cần hỗ trợ các bước song song và hoàn thiện. Ví dụ về Collectors bao gồm:

  • tổng kết, vd Collectors.reducing(0, (x, y) -> x + y)
  • StringBuilder nối thêm, vd Collector.of(StringBuilder::new, StringBuilder::append, StringBuilder::append, StringBuilder::toString)

31
Spliterator (s) cũng cung cấp một cách để truyền phát Iterable không phải là Bộ sưu tập
Bohemian

2
Tôi có nghĩa là "một hoạt động giảm, theo nghĩa là thuật ngữ này có nghĩa là trong bản đồ / giảm"
Louis Wasserman

1
Collectors.ofmột phương pháp cũ của phiên bản beta đã bị xóa hoặc tôi đang thiếu thứ gì đó? Để hoàn thiện, (x,y) -> x+ycó thể được viết là Integer::sum.
Jean-François Savard

3
Er, không, xin lỗi, đó là Collector.of, không phải Collector.of.
Louis Wasserman

2
Ví dụ về Collector của bạn sẽ hữu ích hơn nếu bạn giải thích từng Collector của bạn làm gì.
MiguelMunoz

90

Spliterator về cơ bản có nghĩa là "Iterator có thể chia tách".

Một luồng có thể tự xử lý / xử lý toàn bộ Spliterator, nhưng Spliterator cũng có một phương thức trySplit()sẽ "tách" một phần để người khác (thông thường, một luồng khác) xử lý - khiến cho trình phân tách hiện tại ít hoạt động hơn.

Collectorkết hợp đặc điểm kỹ thuật của một reducechức năng (của sự nổi tiếng giảm bản đồ), với một giá trị ban đầu và một chức năng để kết hợp hai kết quả (do đó cho phép kết quả từ các luồng công việc được phân chia, được kết hợp.)

Ví dụ: Trình thu thập cơ bản nhất sẽ có giá trị ban đầu là 0, thêm số nguyên vào kết quả hiện có và sẽ 'kết hợp' hai kết quả bằng cách thêm chúng. Do đó, tổng hợp một dòng số nguyên.

Xem:


một giá trị để kết hợp hai kết quả?
Jason Law

@JasonLaw - làm rõ! Cám ơn vì sự gợi ý.
Thomas W

5

Sau đây là các ví dụ về việc sử dụng các bộ sưu tập được xác định trước để thực hiện các tác vụ giảm đột biến phổ biến:

 // Accumulate names into a List
 List<String> list = people.stream().map(Person::getName).collect(Collectors.toList());

 // Accumulate names into a TreeSet
 Set<String> set = people.stream().map(Person::getName).collect(Collectors.toCollection(TreeSet::new));

 // Convert elements to strings and concatenate them, separated by commas
 String joined = things.stream()
                       .map(Object::toString)
                       .collect(Collectors.joining(", "));

 // Compute sum of salaries of employee
 int total = employees.stream()
                      .collect(Collectors.summingInt(Employee::getSalary)));

 // Group employees by department
 Map<Department, List<Employee>> byDept
     = employees.stream()
                .collect(Collectors.groupingBy(Employee::getDepartment));

 // Compute sum of salaries by department
 Map<Department, Integer> totalByDept
     = employees.stream()
                .collect(Collectors.groupingBy(Employee::getDepartment,
                                               Collectors.summingInt(Employee::getSalary)));

 // Partition students into passing and failing
 Map<Boolean, List<Student>> passingFailing =
     students.stream()
             .collect(Collectors.partitioningBy(s -> s.getGrade() >= PASS_THRESHOLD));

2
Điều này không trả lời câu hỏi của Op, cộng với không có giải thích hoặc mô tả về bài đăng của bạn.
Sid

4

Giao diện Spliterator- là một tính năng cốt lõi của Luồng .

Các phương thức stream()parallelStream()mặc định được trình bày trong Collectiongiao diện. Các phương thức này sử dụng Spliterator thông qua lệnh gọi đến spliterator():

...

default Stream<E> stream() {
    return StreamSupport.stream(spliterator(), false);
}

default Stream<E> parallelStream() {
    return StreamSupport.stream(spliterator(), true);
}

...

Spliterator là một trình vòng lặp bên trong, ngắt luồng thành các phần nhỏ hơn. Những phần nhỏ hơn có thể được xử lý song song.

Trong số các phương pháp khác, có hai điều quan trọng nhất để hiểu Spliterator:

  • boolean tryAdvance(Consumer<? super T> action) Không giống như Iterator, nó cố gắng thực hiện thao tác với phần tử tiếp theo. Nếu hoạt động được thực hiện thành công, phương thức trả về true. Mặt khác, trả về false- điều đó có nghĩa là không có phần tử hoặc phần cuối của luồng.

  • Spliterator<T> trySplit() Phương pháp này cho phép chia một tập hợp dữ liệu thành nhiều tập nhỏ hơn theo một hoặc một tiêu chí khác (kích thước tệp, số dòng, v.v.).


´Nếu hoạt động được thực hiện thành công..Có lẽ bạn nên điều chỉnh lại cái này. tryAdvance javadoc rõ ràng hơn: Nếu một phần tử còn lại tồn tại, thực hiện hành động đã cho trên nó, trả về true; người khác trả lại sai. Từ chối
Piro nói Phục hồi lại
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.