Aliran Java 8 dan Infinite

1. Gambaran keseluruhan

Dalam artikel ini, kita akan melihat API java.util.Stream dan kita akan melihat bagaimana kita dapat menggunakan konstruk tersebut untuk beroperasi pada aliran data / elemen yang tidak terbatas.

Kemungkinan mengerjakan urutan elemen yang tidak terbatas didasarkan pada fakta bahawa aliran dibina untuk menjadi malas.

Kemalasan ini dicapai dengan pemisahan antara dua jenis operasi yang dapat dilakukan pada aliran: operasi perantaraan dan terminal .

2. Operasi Menengah dan Terminal

Semua Stream operasi dibahagikan kepada pengantara dan terminal operasi dan digabungkan untuk membentuk saluran paip aliran.

Saluran paip terdiri daripada sumber (seperti Koleksi , susunan, fungsi penjana, saluran I / O, atau penjana urutan tak terhingga); diikuti dengan operasi perantaraan sifar atau lebih dan operasi terminal.

2.1. Operasi Pertengahan

Operasi pertengahan tidak dijalankan unit beberapa operasi terminal dipanggil.

Mereka disusun membentuk saluran pelaksanaan Stream . The perantaraan operasi boleh ditambah kepada Stream saluran paip dengan kaedah:

  • penapis ()
  • peta ()
  • peta rata ()
  • berbeza ()
  • disusun ()
  • mengintip ()
  • had()
  • langkau ()

Semua operasi Menengah menjadi malas, jadi mereka tidak akan dijalankan sehingga proses pemprosesan sebenarnya diperlukan.

Pada dasarnya, operasi perantaraan mengembalikan aliran baru. Melaksanakan operasi perantaraan tidak benar-benar melakukan operasi apa pun, melainkan membuat aliran baru yang, ketika dilalui, mengandung unsur aliran awal yang sesuai dengan predikat yang diberikan.

Dengan demikian, melintasi Aliran tidak akan bermula sehingga operasi terminal saluran paip dijalankan.

Itu adalah harta yang sangat penting, sangat penting untuk aliran yang tidak terbatas - kerana ia membolehkan kita membuat aliran yang sebenarnya akan dipanggil hanya apabila operasi Terminal dipanggil.

2.2. Operasi Terminal

Operasi terminal dapat melintasi aliran untuk menghasilkan hasil atau kesan sampingan.

Setelah operasi terminal dilakukan, saluran pipa dianggap habis, dan tidak lagi dapat digunakan. Dalam hampir semua kes, operasi terminal tidak sabar-sabar, menyelesaikan penyebaran sumber data dan memproses saluran paip sebelum kembali.

Kesungguhan operasi terminal penting mengenai aliran tak terbatas kerana pada masa pemprosesan, kita perlu memikirkan dengan teliti jika Stream kita terikat dengan betul , misalnya, transformasi had () . Operasi terminal adalah:

  • untuk setiap()
  • untukEachOrdered ()
  • keArray ()
  • kurangkan ()
  • kumpulkan ()
  • min ()
  • maks ()
  • kira ()
  • anyMatch ()
  • semuaPadan ()
  • tiadaPadan ()
  • cariLama ()
  • cari Mana-mana ()

Setiap operasi ini akan mencetuskan pelaksanaan semua operasi perantaraan.

3. Aliran Tidak Terbatas

Sekarang setelah kita memahami kedua konsep ini - operasi Menengah dan Terminal - kita dapat menulis aliran tak terbatas yang memanfaatkan kemalasan Aliran.

Katakanlah bahawa kita mahu membuat aliran elemen yang tidak terbatas dari sifar yang akan ditingkatkan oleh dua. Maka kita perlu menghadkan urutan itu sebelum memanggil operasi terminal.

Ia adalah penting untuk menggunakan had () kaedah sebelum melaksanakan yang mengumpul () kaedah iaitu operasi terminal, jika tidak, program kami akan disiarkan selama-lamanya:

// given Stream infiniteStream = Stream.iterate(0, i -> i + 2); // when List collect = infiniteStream .limit(10) .collect(Collectors.toList()); // then assertEquals(collect, Arrays.asList(0, 2, 4, 6, 8, 10, 12, 14, 16, 18));

Kami membuat aliran tanpa had menggunakan kaedah iterate () . Kemudian kami memanggil transformasi had () dan operasi mengumpulkan () terminal. Kemudian dalam Senarai yang dihasilkan , kita akan mempunyai 10 elemen pertama dari urutan tak terhingga kerana kemalasan Aliran.

4. Aliran Tak Terbatas Jenis Elemen Khusus

Katakan bahawa kami ingin membuat aliran UUID rawak yang tidak terhingga .

Langkah pertama untuk mencapai ini menggunakan Stream API adalah dengan membuat Pembekal nilai rawak tersebut:

Supplier randomUUIDSupplier = UUID::randomUUID;

Apabila kita menentukan pembekal, kita dapat membuat aliran tanpa batas menggunakan kaedah menghasilkan () :

Stream infiniteStreamOfRandomUUID = Stream.generate(randomUUIDSupplier);

Then we could take a couple of elements from that stream. We need to remember to use a limit() method if we want our program to finish in a finite time:

List randomInts = infiniteStreamOfRandomUUID .skip(10) .limit(10) .collect(Collectors.toList());

We use a skip() transformation to discard first 10 results and take the next 10 elements. We can create an infinite stream of any custom type elements by passing a function of a Supplier interface to a generate() method on a Stream.

6. Do-While – the Stream Way

Let's say that we have a simple do..while loop in our code:

int i = 0; while (i < 10) { System.out.println(i); i++; }

We are printing i counter ten times. We can expect that such construct can be easily written using Stream API and ideally, we would have a doWhile() method on a stream.

Unfortunately, there is no such method on a stream and when we want to achieve functionality similar to standard do-while loop we need to use a limit() method:

Stream integers = Stream .iterate(0, i -> i + 1); integers .limit(10) .forEach(System.out::println);

We achieved same functionality like an imperative while loop with less code, but call to the limit() function is not as descriptive as it would be if we had a doWhile() method on a Stream object.

5. Conclusion

Artikel ini menerangkan bagaimana kita dapat menggunakan Stream API untuk membuat aliran tanpa batas. Ini, apabila digunakan bersama dengan transformasi seperti had () - dapat membuat beberapa senario lebih mudah difahami dan dilaksanakan.

Kod yang menyokong semua contoh ini boleh didapati dalam projek GitHub - ini adalah projek Maven, jadi mudah untuk diimport dan dijalankan sebagaimana adanya.