Pengenalan kepada Java 8 Streams

1. Gambaran keseluruhan

Dalam artikel ini, kita akan melihat dengan cepat salah satu bahagian utama fungsi baru yang ditambahkan Java 8 - Streams.

Kami akan menerangkan tentang aliran dan memperlihatkan penciptaan dan operasi aliran asas dengan contoh mudah.

2. Aliran API

Salah satu ciri baru utama di Java 8 adalah pengenalan fungsi aliran - java.util.stream - yang mengandungi kelas untuk memproses urutan elemen.

Kelas API pusat ialah Aliran. Bahagian berikut akan menunjukkan bagaimana aliran dapat dibuat menggunakan sumber penyedia data yang ada.

2.1. Penciptaan Aliran

Aliran boleh dibuat dari sumber elemen yang berbeza, misalnya koleksi atau susunan dengan bantuan kaedah aliran () dan () :

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

A aliran () kaedah lalai ditambah kepada Collection muka dan membolehkan mewujudkan Stream menggunakan mana-mana koleksi sebagai sumber unsur :

Stream stream = list.stream(); 

2.2. Multi-threading Dengan Aliran

Stream API juga menyederhanakan multithreading dengan menyediakan kaedah parallelStream () yang menjalankan operasi ke atas elemen aliran dalam mod selari.

Kod di bawah memungkinkan untuk menjalankan kaedah doWork () secara selari untuk setiap elemen aliran:

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

Pada bahagian berikut, kami akan memperkenalkan beberapa operasi asas API Aliran.

3. Operasi Aliran

Terdapat banyak operasi berguna yang dapat dilakukan di aliran.

Mereka dibahagikan kepada operasi perantaraan ( aliran balik ) dan operasi terminal (mengembalikan hasil dari jenis yang pasti). Operasi pertengahan membenarkan rantai.

Perlu juga diperhatikan bahawa operasi di aliran tidak mengubah sumbernya.

Inilah contoh ringkas:

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

Oleh itu, kaedah berbeza () mewakili operasi perantaraan, yang mewujudkan aliran baru elemen unik dari aliran sebelumnya. Dan kaedah hitungan () adalah operasi terminal , yang mengembalikan ukuran aliran.

3.1. Pengulangan

API Stream membantu untuk menggantikan untuk , untuk-setiap , dan manakala gelung. Ini memungkinkan untuk menumpukan perhatian pada logik operasi, tetapi tidak pada lelaran terhadap urutan elemen. Sebagai contoh:

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

Kod ini dapat diubah hanya dengan satu baris kod Java 8:

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

3.2. Penapisan

Kaedah penapis () membolehkan kita memilih aliran elemen yang memenuhi predikat.

Sebagai contoh, pertimbangkan senarai 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("");

Kod berikut mewujudkan Stream daripada Senarai , mendapati semua elemen aliran ini yang mengandungi char "d" , dan mewujudkan aliran baru yang mengandungi hanya unsur-unsur ditapis:

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

3.3. Pemetaan

To convert elements of a Stream by applying a special function to them and to collect these new elements into a Stream, we can use the map() method:

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

So, the code above converts Stream to the Stream by applying a specific lambda expression to every element of the initial Stream.

If you have a stream where every element contains its own sequence of elements and you want to create a stream of these inner elements, you should use the flatMap() method:

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

In this example, we have a list of elements of type Detail. The Detail class contains a field PARTS, which is a List. With the help of the flatMap() method, every element from field PARTS will be extracted and added to the new resulting stream. After that, the initial Stream will be lost.

3.4. Matching

Stream API gives a handy set of instruments to validate elements of a sequence according to some predicate. To do this, one of the following methods can be used: anyMatch(), allMatch(), noneMatch(). Their names are self-explanatory. Those are terminal operations that return a 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());

Kod ini menggunakan operasi mengumpulkan terminal () untuk mengurangkan Aliran ke Senarai.

4. Kesimpulan

Dalam artikel ini, kami secara ringkas menyentuh aliran Java - pasti salah satu ciri Java 8 yang paling menarik.

Terdapat banyak contoh lanjutan menggunakan Aliran; tujuan penulisan ini hanyalah untuk memberikan pengenalan yang cepat dan praktikal mengenai perkara yang boleh anda mulakan dengan fungsi dan sebagai titik permulaan untuk meneroka dan belajar lebih lanjut.

Kod sumber yang menyertakan artikel ini terdapat di GitHub.