JavaRush /Blog Java /Random-VI /API luồng

API luồng

Xuất bản trong nhóm
API luồng - 1

API luồng là gì?

API Stream là một cách mới để làm việc với cấu trúc dữ liệu theo kiểu chức năng. API luồng (mô tả về cách thức mà một chương trình máy tính có thể giao tiếp với chương trình khác), cốt lõi của nó là một luồng dữ liệu. Bản thân thuật ngữ “luồng” khá mơ hồ trong lập trình nói chung và trong Java nói riêng.
API luồng - 1
Với sự ra đời của Java 8, API Stream cho phép các lập trình viên viết ngắn gọn hơn nhiều những gì trước đây cần nhiều dòng mã, cụ thể là để đơn giản hóa cách làm việc với các tập dữ liệu, đặc biệt là đơn giản hóa việc lọc, sắp xếp và các hoạt động thao tác dữ liệu khác. Nếu không có các thao tác trung gian, bạn có thể và nên thường xuyên thực hiện mà không cần luồng, nếu không mã sẽ phức tạp hơn so với không có luồng.
API luồng - 2
Chính xác thì tôi nên bắt đầu từ đâu? Từ việc tạo một phiên bản Stream, dựa trên bộ sưu tập, mảng hoặc phương thức chúng ta cần và nơi dữ liệu sẽ được lấy từ đó:
List<String> list = new ArrayList<String>();
       list.add("One");
       list.add("Two");
       list.add("Three");
       list.add("Four");
       list.add("Five");
       list.add("Six");
       list.add("Seven");
       list.add("Eight");
       list.add("Nine");
       list.add("Ten");
       Stream stream = list.stream();
Như đã đề cập ở trên, API Stream cho phép bạn giảm số dòng mã. Ví dụ với một luồng:
IntStream.of(50, 60, 70, 80, 90, 100, 110, 120).filter(x -> x < 90).map(x -> x + 10)
.limit(3).forEach(System.out::print);
Ví dụ không có chủ đề:
int[] arr = {50, 60, 70, 80, 90, 100, 110, 120
	int count = 0;
	for (int x : arr) {
	    if (x >= 90) continue;
	    x += 10;
	    count++;
	    if (count > 3) break;
	    System.out.print(x);
	}
Các cách có thể để tạo Luồng:
API luồng - 3
  • Luồng trống:Stream.empty()
  • Truyền phát từ Danh sách:list.stream()
  • Truyền phát từ Bản đồ:map.entrySet().stream()
  • Truyền phát từ mảng:Arrays.stream(array)
  • Truyền phát từ các phần tử được chỉ định:Stream.of("1", "2", "3")
Ngoài ra còn có các toán tử (về cơ bản là các phương thức của lớp Stream), các toán tử có thể được chia thành hai nhóm:
  • Trung gian (còn gọi là "lười biếng") - xử lý các phần tử đến và trả về luồng. Có thể có nhiều toán tử trung gian trong chuỗi xử lý phần tử.
  • Terminal (“terminal”, còn được gọi là “eager”) - xử lý các phần tử và kết thúc luồng, do đó chỉ có thể có một toán tử đầu cuối trong chuỗi.
Ví dụ:
1.List<String> list = new ArrayList<String>();
2.list.add("One");11.list.add("Ten");
12.Stream stream = list.stream();
13.stream.filter(x-> x.toString().length() == 3).forEach(System.out::println);
Những gì đang xảy ra ở đây:
  • 1 - tạo danh sách list;
  • 2-11 - điền dữ liệu thử nghiệm vào đó;
  • 12 - tạo một đối tượng Stream;
  • 13 - phương thức filter(bộ lọc) - toán tử trung gian, xtương đương với một phần tử của bộ sưu tập để liệt kê (như với for each) và sau -> chúng tôi chỉ ra cách bộ sưu tập của chúng tôi được lọc và vì đây là toán tử trung gian nên bộ sưu tập được lọc sẽ đi sâu hơn vào phương thức , forEachđến lượt nó là phần cuối (cuối cùng) tương tự của phép liệt kê for each(Biểu thức viết System.out::printlntắt của:, x-> System.out.println(x))lần lượt đi qua tất cả các phần tử của bộ sưu tập được truyền cho nó và hiển thị nó)
API luồng - 5
Điểm quan trọng:
  • Quá trình xử lý sẽ không bắt đầu cho đến khi toán tử đầu cuối được gọi. list.stream().filter(s -> s > 5)(sẽ không lấy một phần tử nào từ danh sách);
  • Một phiên bản của luồng không thể được sử dụng nhiều lần =( ;
  • API luồng - 6

    Vì vậy, mỗi khi nó mới:

    list.stream().filter(x-> x.toString().length() == 3).forEach(System.out::println);
    list.stream().forEach(x -> System.out.println(x));
  • Có thể có nhiều toán tử trung gian được gọi trên một luồng, trong khi chỉ có một toán tử đầu cuối:

    stream.filter(x-> x.toString().length() == 3).map(x -> x + " - the length of the letters is three").forEach(x -> System.out.println(x));
Tiếp theo, hãy xem xét một số toán tử trung gian:
API luồng - 7
  • filter(Predicate predicate)lọc luồng, chỉ truyền những phần tử đáp ứng điều kiện (Vị ngữ là giao diện chức năng tích hợp được thêm vào gói trong Java SE 8. java.util.functionKiểm tra giá trị cho “ true ” và “ false ”);
  • map(Function mapper)cho phép tạo một hàm mà chúng ta sẽ thay đổi từng thành phần và bỏ qua nó thêm (Giao diện chức năng thể Function<T,R>hiện chức năng chuyển đổi từ một đối tượng loại T sang đối tượng loại R)
  • flatMap(Function<T, Stream<R>> mapper)- như trong trường hợp map, chúng được sử dụng để chuyển đổi thành luồng nguyên thủy.
Ví dụ: khi làm việc với một mảng các luồng (mảng, danh sách, v.v.), nó sẽ chuyển đổi chúng thành một luồng (mảng, danh sách, v.v.) [stream1,stream2,stream3,stream4] => stream:
String[] array = {"Java", "Ruuuuussshhh"};
Stream<String> streamOfArray = Arrays.stream(array);
streamOfArray.map(s->s.split("")) //Convert the word to an array of letters
        .flatMap(Arrays::stream).distinct() //aligns each generated thread into a single thread
        .collect(Collectors.toList()).forEach(System.out::println);
Trong khi mapnó chuyển đổi thành danh sách các chủ đề (chính xác hơn là <Stream>các chủ đề) [stream1,stream2,stream3,stream4] =>Stream.of(stream1,stream2,stream3,stream4):
String[] array = {"Java", "Ruuuuussshhh"};
Stream<String> streamOfArray = Arrays.stream(array);
streamOfArray.map(s->s.split("")) //Convert the word to an array of letters
        .map(Arrays::stream).distinct() //Make the array into a separate thread
        .collect(Collectors.toList()).forEach(System.out::println);
Một điểm khác biệt so với map, bạn có thể chuyển đổi một phần tử thành 0, một hoặc nhiều phần tử khác. Để chuyển đổi một phần tử thành phần tử 0, bạn cần trả về nullhoặc một luồng trống. Để chuyển đổi thành một phần tử, bạn cần trả về một luồng từ một phần tử, ví dụ: thông qua Stream.of(x). Để trả về một số phần tử, bạn có thể tạo luồng có các phần tử này bằng bất kỳ cách nào. Cùng một phương thức FlatMap, nhưng dành cho Double, Integer và Long:
  • FlatMapToDouble(Trình ánh xạ hàm)
  • FlatMapToInt(Trình ánh xạ hàm)
  • FlatMapToLong(Trình ánh xạ hàm)
Và một ví dụ khác để so sánh, FlatMap:
Stream.of(2, 3, 0, 1, 3)
        .flatMapToInt(x -> IntStream.range(0, x))
        .forEach(System.out::print);// 010120012
  • IntStream.range(0,x) – xuất các phần tử từ 0 (đã bao gồm) đến x (không bao gồm) vào luồng;

    bản đồ:

    Stream.of(2, 3, 0, 1, 3)
            .map(x -> IntStream.range(0, x))
            .forEach(System.out::print);//list of streams (streams);
  • limit(long maxSize) – giới hạn luồng theo số phần tử:

    stream.limit(5).forEach(x -> System.out.println(x));
  • Skip(long n) – bỏ qua n phần tử:

    stream.skip(3).forEach(x -> System.out.println(x));
  • được sắp xếp()

  • được sắp xếp (Bộ so sánh so sánh) - sắp xếp luồng (sắp xếp như TreeMap):

    stream.sorted().forEach(x -> System.out.println(x));
  • khác biệt() - kiểm tra luồng xem tính duy nhất của các phần tử (loại bỏ sự lặp lại của các phần tử);

  • dropwhile(Predicate predicate) - bỏ qua các phần tử thỏa mãn điều kiện (xuất hiện trong java 9, Giao diện chức năng Predicate<T> kiểm tra xem một số điều kiện có được đáp ứng hay không. Nếu nó được đáp ứng, thì trả về true. Biểu thức lambda nhận một đối tượng thuộc loại T làm tham số:

    Predicate<Integer> isPositive = x -> x > 0;
           System.out.println(isPositive.test(3)); // true
           System.out.println(isPositive.test(-9)); // false
Nhà khai thác thiết bị đầu cuối:
API luồng - 8
  • forEach(Consumer action) – tương tự for each (Consumer<T> thực hiện một số hành động trên một đối tượng thuộc loại T mà không trả lại bất cứ thứ gì);

  • count() – trả về số phần tử luồng:

    System.out.println(stream.count());

  • coll(Collector Collector) – phương thức thu thập tất cả các phần tử vào một danh sách, tập hợp hoặc bộ sưu tập khác, nhóm các phần tử theo tiêu chí nào đó, kết hợp mọi thứ thành một chuỗi, v.v.:

    List<String> list = Stream.of(One,Two,Three).collect(Collectors.toList());
  • collect(Supplier supplier, BiConsumer accumulator, BiConsumer combiner)- giống như , collect(collector)chỉ có các tham số được chia nhỏ để thuận tiện ( supplierví dụ: cung cấp các đối tượng mới (vùng chứa), new ArrayList()thêm accumulatormột phần tử vào vùng chứa, combinerkết hợp các phần của luồng với nhau);

  • giảm (T nhận dạng, bộ tích lũy BinaryOperator) - chuyển đổi tất cả các phần tử của luồng thành một đối tượng (tính tổng của tất cả các phần tử hoặc tìm phần tử tối thiểu), trước tiên lấy đối tượng và phần tử identityđầu tiên của luồng, áp dụng hàm accumulatoridentitytrở thành kết quả của nó. Sau đó mọi thứ tiếp tục cho các phần tử còn lại.

    int sum = Stream.of(1, 2, 3, 4, 5).reduce(10, (acc, x) -> acc + x);// = 25
  • reduce(BinaryOperator accumulator)— phương thức tương tự như trên nhưng phương thức ban đầu bị thiếu identity, nó là phần tử đầu tiên của luồng

    Optional min(Comparator comparator)
    Tùy chọn tối đa (Bộ so sánh so sánh) tìm kiếm phần tử tối thiểu/tối đa dựa trên bộ so sánh đã qua;

  • findFirst()– lấy ra phần tử đầu tiên của luồng:

    Stream.of(1, 2, 3, 4, 9).findFirst();
  • allMatch(Predicate predicate)— trả về true nếu tất cả các phần tử của luồng thỏa mãn điều kiện. Nếu gặp bất kỳ phần tử nào mà kết quả của việc gọi hàm vị ngữ là sai thì toán tử sẽ ngừng quét các phần tử đó và trả về false :

    Stream.of(1, 2, 3, 4, 9).allMatch(x -> x <= 7);//false
  • anyMatch(Predicate predicate)— sẽ trả về true nếu ít nhất một phần tử của luồng thỏa mãn điều kiện predicate:

    Stream.of(1, 2, 3, 4, 9).anyMatch(x -> x >= 7);//true
  • noneMatch(Predicate predicate)— sẽ trả về true nếu sau khi xem qua tất cả các phần tử của luồng, không có phần tử nào thỏa mãn điều kiện predicate:

    Stream.of(1, 2, 3, 4, 9).noneMatch(x -> x >= 7);//false
Và cuối cùng tôi muốn xem xét một số phương pháp Collectors:
  • toList()- tập hợp các phần tử thành List:

    List<Integer> list = Stream.of(99, 2, 3).collect(Collectors.toList());
  • toSet()- tập hợp các phần tử thành một tập hợp:

    Set<Integer> set = Stream.of(99, 2, 3).collect(Collectors.toSet());
  • counting()- Đếm số phần tử:

    Long count = Stream.of("1", "2", "3", "4").collect(Collectors.counting());
  • joining()

  • joining(CharSequence delimiter)

  • joining(CharSequence delimiter, CharSequence prefix, CharSequence suffix)- tập hợp các phần tử thành một dòng. Ngoài ra, bạn có thể chỉ định dấu phân cách cũng như tiền tố và hậu tố cho toàn bộ chuỗi:

    String a = Stream.of("s", "u" ,"p", "e", "r").collect(Collectors.joining());
           System.out.println(a); // super
    
           String b = Stream.of("s", "u", "p", "e", "r").collect(Collectors.joining("-"));
           System.out.println(b); // s-u-p-e-r
    
           String c = Stream.of("s", "u", "p", "e", "r").collect(Collectors.joining(" -> ", "[ ", " ]"));
           System.out.println(c);  // [ s -> u -> p -> e -> r ]
  • summingInt(ToIntFunction mapper)

  • summingLong(ToLongFunction mapper)

  • summingDouble(ToDoubleFunction mapper)- một bộ sưu tập chuyển đổi các đối tượng thành int/long/double và tính tổng.

Liên kết hữu ích: Tái bút: đừng ngại cho chúng tôi lượt thích nhé ^ : ^
Bình luận
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION