Streams API trong Java 8 là một bước tiến lớn của ngôn ngữ lập trình Java và liên quan đến nhiều khía cạnh khác nhau, nên chúng tôi cần kéo dài thêm chủ đề này. Nếu bạn là lập trình viên C# trên nền .NET framework vào năm 2008, có thể bạn từng háo hức tìm hiểu LINQ. Từ năm 2014 trở về sau, lập trình viên Java cũng được tận hưởng cảm giác tương tự với Java Streams API.
Tôi đã từng rất say mê C#, trong ký ức xưa cũ, tôi tìm tên những nhân viên có chứa từ “Văn” sử dụng cú pháp LINQ:
1
2
|
string[] employeeList = {“Nguyễn Văn Còn”, “Phạm Văn Đoan”, “Nguyễn Văn Minh”, “Đoàn Minh Huệ”};
List filteredNames = employeeList.Where(c => c.Contains(“Văn”)).ToList();
|
Giờ đây với Java 8 Streams API:
1
2
3
4
|
String[] employeeList = {“Nguyễn Văn Còn”, “Phạm Văn Đoan”, “Nguyễn Văn Minh”, “Đoàn Minh Huệ”};
List filteredNames = stream(employeeList)
.filter(c –> c.contains(“Văn”))
.collect(toList());
|
Sự linh hoạt, hữu dụng của Streams API thể hiện ở số lượng “pattern” rất đa dạng. “pattern” tạm hiểu là cách dùng, cách thức tổ hợp, phối hợp các phương thức để mang đến kết quả mong muốn. Phần nội dung này để trình bày thêm về các “pattern”.

Dòng suối (stream)
Có nhiều cách để khởi tạo dòng nước (stream):
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
|
// Khởi tạo dòng (stream) từ mảng (array).
Arrays.stream(stringArray);
// Khởi tạo dòng số nguyên (stream of integer numbers) từ khoảng giá trị.
IntStream.range(9, 42);
// Khởi tạo dòng (stream) từ List<T>
employeeList.stream();
// Khởi tạo dòng nước (stream) từ tập hợp các file.
Files.walks();
// Khởi tạo dòng nước (stream) từ Spliterator<T> – Một interface mới trong bộ Collections.
java.util.Spliterator()
// Khởi tạo dòng (stream) từ tập hợp hữu hạn giá trị.
Streams.of(“Nguyễn Văn Còn”, “Đoàn Minh Huệ”, “Nguyễn Văn Cảnh”, “Nguyễn Văn Hải”);
// Sử dụng chức năng của Supplier (đã kết hợp với Java 8 Lamba expression).
Supplier<Stream<String>> employeeList = () –> Stream.of(“Nguyễn Văn Còn”, “Đoàn Minh Huệ”, “Nguyễn Văn Cảnh”, “Nguyễn Văn Hải”);
|
(Supplier là interface class mới xuất hiện từ Java 8. Xem javadoc: https://docs.oracle.com/javase/8/docs/api/java/util/function/Supplier.html).
Tìm các nhân viên có tên bắt đầu bằng chữ “H”:
1
2
3
4
5
6
7
8
9
|
Stream.of(“Hùng”, “Trường”, “Khánh”, “Hằng”, “Đoan”)
.map(s–>s.toUpperCase())
.filter(s–>s.startsWith(“H”))
.forEach(System.out::println);
// Kết quả:
//HÙNG
//HẰNG
|
Ghi chú: Khi sử dụng cú pháp
1
|
System.out::println
|
chúng ta đã sử dụng đến kỹ thuật Method references (tham chiếu phương thức, mới có từ Java 8), thể hiện qua ký hiệu 2 dấu 2 chấm :: Xem thêm tài liệu từ Oracle: https://docs.oracle.com/javase/tutorial/java/javaOO/methodreferences.html . Nếu không muốn dùng cú pháp “tham chiếu phương thức”, bạn có thể dùng cú pháp Lambda expression vẫn cho kết quả như cũ:
1
|
.forEach(s–> System.out.println(s));
|
Stream characteristics – Lọc dòng nước theo điều kiện
Trong phần trước, chúng ta đã sử dụng ví dụ đếm số lượng các ký tự phân biệt:
1
2
3
4
5
6
|
String foo = “smartjobdotvn”;
IntStream letters = foo.chars();
long counter = letters.distinct().count();
// Nhưng chỉ có 11 ký tự sau khi loại bỏ trùng lặp.
System.out.println(“Số ký tự có mặt trong chuỗi (đã loại bỏ trùng lặp): “ + counter);
|
Chúng ta đã “lọc dòng nước” theo điều kiện distinct() (phân biệt/khác biệt). Danh sách dài hơn các điều kiện lọc mà bạn có thể sử dụng trong Streams API là:
1
2
3
4
5
6
7
8
|
DISTINCT
CONCURENT
IMMUTABLE
NONNULL
ORDERED
SIZED
SORTED
SUBSIZED
|
cũng chính là các field do class interface Spliterator cung cấp. Xem Javadocs: https://docs.oracle.com/javase/8/docs/api/java/util/Spliterator.html Mục “Field Summary”.
Đỗ Như Vý – developer tại SmartJob
c#,
java,
Java 8,
Lambda Expression,
Linq,
method references,
streams,
Streams API,