1. Những đổi mới trong Java 8: Lập trình hàm

Với việc phát hành Java 8, ngôn ngữ này đã nhận được sự hỗ trợ mạnh mẽ cho lập trình chức năng . Bạn thậm chí có thể nói rằng nó đã nhận được sự hỗ trợ đã được chờ đợi từ lâu cho lập trình chức năng. Viết mã trở nên nhanh hơn, mặc dù mã khó đọc hơn 🙂

Trước khi học lập trình hàm trong Java, chúng tôi khuyên bạn nên hiểu rõ ba điều sau:

  1. OOP, kế thừa và giao diện ( Cấp độ 1-2 trong nhiệm vụ Java Core ).
  2. Triển khai phương thức mặc định trong một giao diện .
  3. Các lớp bên trong và ẩn danh .

Tin tốt là bạn không cần phải biết tất cả những điều này để sử dụng nhiều tính năng của lập trình hàm trong Java. Tin xấu là sẽ rất khó để hiểu chính xác mọi thứ được sắp xếp như thế nào và mọi thứ hoạt động như thế nào nếu không biết về các lớp ẩn danh bên trong.

Trong các bài học sắp tới, chúng ta sẽ tập trung vào việc sử dụng các tính năng lập trình hàm của Java dễ dàng và đơn giản như thế nào mà không cần hiểu sâu về cách thức hoạt động của nó.

Phải mất hàng tháng để hiểu tất cả các sắc thái của lập trình chức năng trong Java. Bạn có thể học cách đọc mã như vậy trong vài giờ. Vì vậy, chúng tôi đề nghị bắt đầu nhỏ. Ngay cả khi đó là với các luồng I/O.


2. Luồng I/O: đường ống luồng

Bạn có nhớ rằng đã có lần bạn học về luồng I/O: InputStream, OutputStream, Reader, Writerv.v. không?

Có các lớp luồng đọc dữ liệu từ các nguồn dữ liệu , chẳng hạn như FileInputSteamvà có các luồng dữ liệu trung gian đọc dữ liệu từ các luồng khác, chẳng hạn như InputStreamReaderBufferedReader.

Các luồng này có thể được tổ chức thành các đường ống xử lý dữ liệu. Ví dụ, như thế này:

FileInputStream input = new FileInputStream("c:\\readme.txt");
InputStreamReader reader = new InputStreamReader(input);
BufferedReader buff = new BufferedReader(reader);

String text = buff.readLine();

Điều quan trọng cần lưu ý là trong một vài dòng mã đầu tiên, chúng ta chỉ đang xây dựng một chuỗi các Streamđối tượng. Dữ liệu chưa được chuyển qua đường ống.

Nhưng ngay khi chúng ta gọi buff.readLine()phương thức, điều sau đây sẽ xảy ra:

  1. Đối BufferedReadertượng gọi read()phương thức trên InputStreamReaderđối tượng
  2. Đối InputStreamReadertượng gọi read()phương thức trên FileInputStreamđối tượng
  3. Đối FileInputStreamtượng bắt đầu đọc dữ liệu từ tệp

Nói cách khác, không có chuyển động của dữ liệu dọc theo đường dẫn luồng cho đến khi chúng tôi bắt đầu gọi các phương thức như read()hoặc readLine(). Việc xây dựng đơn thuần đường ống truyền phát không truyền dữ liệu qua nó. Bản thân các luồng không lưu trữ dữ liệu. Họ chỉ đọc từ những người khác.

Bộ sưu tập và luồng

Bắt đầu với Java 8, có thể lấy luồng để đọc dữ liệu từ các bộ sưu tập (và không chỉ từ chúng). Nhưng đây không phải là điều thú vị nhất. Nó thực sự có thể dễ dàng và đơn giản xây dựng các chuỗi luồng dữ liệu phức tạp. Và khi làm như vậy, mã trước đây mất 5-10 dòng giờ có thể được viết trong 1-2 dòng.

Ví dụ tìm chuỗi dài nhất trong danh sách chuỗi:

Tìm chuỗi dài nhất
ArrayList<String> list = new ArrayList<String>();
Collections.addAll(list, "Hello", "how's", "life?");
String max = list.stream().max((s1, s2)-> s1.length()-s2.length()).get();
ArrayList<String> list = new ArrayList<String>();
Collections.addAll(list, "Hello", "how's", "life?");
Stream<String> stream = list.stream();
Optional<String> optional = stream.max((s1, s2)-> s1.length()-s2.length());
String max = optional.get();

3. Streamgiao diện

Hỗ trợ mở rộng của Java 8 cho các luồng được triển khai bằng cách sử dụng Stream<T>giao diện, trong đó Ttham số loại cho biết loại dữ liệu được truyền trong luồng. Nói cách khác, một luồng hoàn toàn độc lập với loại dữ liệu mà nó đi qua.

Để lấy một đối tượng luồng từ một bộ sưu tập , chỉ cần gọi stream()phương thức của nó. Mã trông đại khái như thế này:

Stream<Type> name = collection.stream();
Nhận luồng từ bộ sưu tập

Trong trường hợp này, bộ sưu tập sẽ được coi là nguồn dữ liệu của luồng và đối Stream<Type>tượng sẽ là công cụ để lấy dữ liệu từ bộ sưu tập dưới dạng luồng dữ liệu.

ArrayList<String> list = new ArrayList<String>();
Collections.addAll(list, "Hello", "how's", "life?");
Stream<String> stream = list.stream();

Nhân tiện, bạn có thể lấy luồng không chỉ từ bộ sưu tập mà còn từ mảng . Để làm điều này, bạn cần sử dụng phương pháp. Ví dụ:Arrays.stream()

Stream<Type> name = Arrays.stream(array);
Lấy một luồng từ một mảng

Trong trường hợp này, mảng sẽ được coi là nguồn dữ liệu cho luồng có tên name.

Integer[] array = {1, 2, 3};
Stream<Integer> stream = Arrays.stream(array);

Không có dữ liệu nào được di chuyển khi Stream<Type>đối tượng được tạo. Chúng tôi chỉ cần có một đối tượng luồng để bắt đầu xây dựng một đường dẫn luồng.