Pengantar Aliran Java 8

1. Ikhtisar

Pada artikel ini, kita akan melihat sekilas salah satu bagian utama dari fungsionalitas baru yang ditambahkan Java 8 - Streams.

Kami akan menjelaskan tentang apa streaming itu dan memamerkan pembuatan dan operasi aliran dasar dengan contoh sederhana.

2. API Aliran

Salah satu fitur baru utama di Java 8 adalah pengenalan fungsionalitas aliran - java.util.stream - yang berisi kelas untuk memproses urutan elemen.

Kelas API pusat adalah Stream. Bagian berikut akan menunjukkan bagaimana aliran dapat dibuat menggunakan sumber penyedia data yang ada.

2.1. Pembuatan Streaming

Aliran dapat dibuat dari sumber elemen yang berbeda misalnya kumpulan atau larik dengan bantuan metode aliran () dan () :

String[] arr = new String[]{"a", "b", "c"}; Stream stream = Arrays.stream(arr); stream = Stream.of("a", "b", "c");

Sebuah aliran () metode standar ditambahkan ke Koleksi antarmuka dan memungkinkan menciptakan Streaming menggunakan koleksi apapun sebagai sumber unsur :

Stream stream = list.stream(); 

2.2. Multi-threading Dengan Streams

Stream API juga menyederhanakan multithreading dengan menyediakan metode parallelStream () yang menjalankan operasi pada elemen aliran dalam mode paralel.

Kode di bawah ini memungkinkan untuk menjalankan metode doWork () secara paralel untuk setiap elemen aliran:

list.parallelStream().forEach(element -> doWork(element));

Di bagian berikut, kami akan memperkenalkan beberapa operasi API Aliran dasar.

3. Operasi Stream

Ada banyak operasi berguna yang dapat dilakukan di aliran.

Mereka dibagi menjadi operasi perantara ( aliran balik ) dan operasi terminal (mengembalikan hasil dari tipe tertentu). Operasi menengah memungkinkan perangkaian.

Perlu juga dicatat bahwa operasi pada aliran tidak mengubah sumbernya.

Berikut contoh singkatnya:

long count = list.stream().distinct().count();

Jadi, metode different () mewakili operasi perantara, yang membuat aliran baru elemen unik dari aliran sebelumnya. Dan metode count () adalah operasi terminal , yang mengembalikan ukuran aliran.

3.1. Iterasi

API aliran membantu untuk menggantikan untuk , untuk-masing , dan sementara loop. Ini memungkinkan berkonsentrasi pada logika operasi, tetapi tidak pada iterasi atas urutan elemen. Sebagai contoh:

for (String string : list) { if (string.contains("a")) { return true; } }

Kode ini dapat diubah hanya dengan satu baris kode Java 8:

boolean isExist = list.stream().anyMatch(element -> element.contains("a"));

3.2. Penyaringan

Metode filter () memungkinkan kita memilih aliran elemen yang memenuhi predikat.

Misalnya, perhatikan daftar berikut:

ArrayList list = new ArrayList(); list.add("One"); list.add("OneAndOnly"); list.add("Derek"); list.add("Change"); list.add("factory"); list.add("justBefore"); list.add("Italy"); list.add("Italy"); list.add("Thursday"); list.add(""); list.add("");

Kode berikut menciptakan Streaming dari Daftar , menemukan semua elemen dari aliran ini yang mengandung char “d” , dan menciptakan aliran baru yang hanya berisi elemen disaring:

Stream stream = list.stream().filter(element -> element.contains("d"));

3.3. Pemetaan

Untuk mengubah elemen Stream dengan menerapkan fungsi khusus padanya dan mengumpulkan elemen baru ini menjadi Stream , kita bisa menggunakan metode map () :

List uris = new ArrayList(); uris.add("C:\\My.txt"); Stream stream = uris.stream().map(uri -> Paths.get(uri));

Jadi, kode di atas mengonversi Stream ke Stream dengan menerapkan ekspresi lambda tertentu ke setiap elemen Stream awal .

Jika Anda memiliki aliran di mana setiap elemen berisi urutan elemennya sendiri dan Anda ingin membuat aliran elemen dalam ini, Anda harus menggunakan metode flatMap () :

List details = new ArrayList(); details.add(new Detail()); Stream stream = details.stream().flatMap(detail -> detail.getParts().stream());

Dalam contoh ini, kami memiliki daftar elemen tipe Detail . Kelas Detail berisi bidang PARTS , yang merupakan Daftar . Dengan bantuan metode flatMap () , setiap elemen dari bidang PARTS akan diekstraksi dan ditambahkan ke aliran baru yang dihasilkan. Setelah itu, Aliran awal akan hilang .

3.4. Sesuai

Stream API memberikan seperangkat instrumen yang berguna untuk memvalidasi elemen urutan berdasarkan beberapa predikat. Untuk melakukan ini, salah satu metode berikut dapat digunakan: anyMatch (), allMatch (), noneMatch (). Nama mereka cukup jelas. Itu adalah operasi terminal yang mengembalikan boolean :

boolean isValid = list.stream().anyMatch(element -> element.contains("h")); // true boolean isValidOne = list.stream().allMatch(element -> element.contains("h")); // false boolean isValidTwo = list.stream().noneMatch(element -> element.contains("h")); // false

For empty streams, the allMatch() method with any given predicate will return true:

Stream.empty().allMatch(Objects::nonNull); // true

This is a sensible default, as we can't find any element that doesn't satisfy the predicate.

Similarly, the anyMatch() method always returns false for empty streams:

Stream.empty().anyMatch(Objects::nonNull); // false

Again, this is reasonable, as we can't find an element satisfying this condition.

3.5. Reduction

Stream API allows reducing a sequence of elements to some value according to a specified function with the help of the reduce() method of the type Stream. This method takes two parameters: first – start value, second – an accumulator function.

Imagine that you have a List and you want to have a sum of all these elements and some initial Integer (in this example 23). So, you can run the following code and result will be 26 (23 + 1 + 1 + 1).

List integers = Arrays.asList(1, 1, 1); Integer reduced = integers.stream().reduce(23, (a, b) -> a + b);

3.6. Collecting

The reduction can also be provided by the collect() method of type Stream. This operation is very handy in case of converting a stream to a Collection or a Map and representing a stream in the form of a single string. There is a utility class Collectors which provide a solution for almost all typical collecting operations. For some, not trivial tasks, a custom Collector can be created.

List resultList = list.stream().map(element -> element.toUpperCase()).collect(Collectors.toList());

Kode ini menggunakan operasi terminal collect () untuk mengurangi Stream ke Daftar.

4. Kesimpulan

Pada artikel ini, kami secara singkat menyentuh aliran Java - pasti salah satu fitur Java 8 yang paling menarik.

Ada banyak contoh lebih lanjut dalam menggunakan Stream; tujuan dari artikel ini hanyalah untuk memberikan pengenalan yang cepat dan praktis tentang apa yang dapat Anda lakukan dengan fungsionalitas tersebut dan sebagai titik awal untuk mengeksplorasi dan mempelajari lebih lanjut.

Kode sumber yang menyertai artikel tersedia di GitHub.