Tong Hoang Vu
Tong Hoang Vu's blog

Tong Hoang Vu's blog

Lấy ra stream từ nguồn dữ liệu

Lấy ra stream từ nguồn dữ liệu

Java Stream API

Tong Hoang Vu's photo
Tong Hoang Vu
·Sep 11, 2021·

4 min read

Subscribe to my newsletter and never miss my upcoming articles

Bài trước mình đã giới thiệu về phần lý thuyết của Java stream. Các bạn cũng biết là để xử lý stream sẽ gồm 3 bước là lấy ra stream, biến đổi stream và tổng hợp stream thành kết quả. Và bài viết hôm nay sẽ trình bày về bước đầu tiên, làm sao để lấy ra được stream từ nguồn dữ liệu.

1. Các loại stream

Phần này hiểu cơ bản là được, cũng không có gì đặc biệt. Tùy vào cách chia, ví dụ chia theo loại element thì có:

  • Object stream là stream gồm các phần tử Object hoặc wrapper class
  • Primitive stream (sẽ nói sau) là stream gồm các phần tử primtive

Nếu chia theo tính song song thì có:

  • Sequential stream xử lý tuần tự
  • Parallel stream có xử lý song song

Những loại này cũng không khó, mình sẽ nhắc lại trong các bài tiếp theo.

2. Lấy ra stream

2.1. Nguồn dữ liệu

Sóng bắt đầu từ gió, stream bắt đầu từ đâu?

Muốn xử lý stream thì cần lấy ra stream. Nhưng ở bài trước có nói, stream không chứa dữ liệu, chỉ xử lý dữ liệu thôi, vậy dữ liệu đâu ra để xử lý? Do đó, cần có một nguồn dữ liệu (data source), và lấy ra stream từ đó.

Ví dụ một số nguồn dữ liệu như:

  • Array
  • Collection như List, Set,...
  • Các hàm generation ra vô hạn
  • File, IO stream,...
  • ...

2.2. stream() method

Với các class nguồn dữ liệu trên, hầu hết đều hỗ trợ method có tên là stream(). Method này sẽ trả ra một đối tượng Stream<T> đại diện cho stream được lấy ra.

// Với collection
List<Integer> nums = List.of(1, 2, 3, 4);
nums.stream(); // Stream<Integer>

// Với array hơi khác
Integer[] primes = new Integer[] { 2, 3, 5, 7 };
Arrays.stream(primes); // Stream<Integer>

Với collection, Java làm được điều này nhờ có tính năng default method cho interface (cũng Java 8 luôn). Các bạn có thể tìm hiểu thêm.

Ngoài ra thường có stream() thì sẽ đi kèm parallelStream(), trả về stream song song thay vì tuần tự.

// Tuy nhiên cả 2 kiểu trả về đều là Stream<Integer>
// Chỉ khác là stream song song thì có đánh dấu parallel
// Để java biết và xử lý song song thôi
nums.stream();
nums.parallelStream();

2.3. Các static method của Stream class

Ngoài việc lấy ra stream từ source như trên, chúng ta còn có thể tự tạo ra stream bằng các static method của Stream class. Xem ví dụ sau nhé, chứ phần này giải thích hơi dài dòng.

Stream<Object> s0 = Stream.empty(); // Tạo stream rỗng
Stream<Integer> s1 = Stream.of(2, 3, 5, 7); // Có vài giá trị

// Generate ra stream theo công thức bằng Supplier<T>
Stream<Double> s2 = Stream.generate(() -> Math.random());

Ngoài ra còn có thể nối stream hoặc dùng builder để tạo stream. Có các static method tương ứng trong Stream class.

3. Primitive stream

Class Stream<T> có generic, do đó kiểu dữ liệu của phần tử sẽ phải là object hoặc wrapper class. Trong các trường hợp đơn giản, ví dụ stream chỉ gồm các số, thì dùng wrapper class như Integer, Double,... sẽ chậm và không tối ưu (do autoboxing, unboxing).

Trong trường hợp đó, nên dùng primitive stream thay thế. Thay vì dùng Stream<Integer>, hãy dùng primitive stream tương ứng là IntStream (ngoài ra còn có LongStreamDoubleStream nữa).

Cách hoạt động cũng tương tự như stream object, nhưng cho hiệu suất tốt hơn, và có thêm các operation riêng như sum().

// Tạo IntStream từ array
int[] nums = new int[] { 2, 3, 5, 7 };
Arrays.stream(nums); // IntStream, không phải Stream<Integer>

// Cũng có các static method của IntStream như trên
IntStream.empty();
IntStream.of(1, 2, 3, 4);

// Tạo từ một range
IntStream.range(2, 10); // Từ 2 - 9
IntStream.rangeClosed(2, 10); // Từ 2 - 10

Stream object có thể chuyển sang primitive stream bằng các operation như mapToInt(), mapToDouble(),... và ngược lại bằng boxed().


Bài viết hôm nay tới đây là hết rùi. Trong bài mình đã tóm tắt sơ bộ về cách lấy ra stream từ nguồn dữ liệu nào đó. Tiếp tục ủng hộ tui và series này bằng cách like và share nhé. Thank you 😘

 
Share this