Pengantar StreamEx

1. Ikhtisar

Salah satu fitur paling menarik dari Java 8 adalah API Stream - yang, sederhananya, adalah alat yang ampuh untuk memproses urutan elemen.

StreamEx adalah pustaka yang menyediakan fungsionalitas tambahan untuk API Stream standar bersama dengan peningkatan kinerja.

Berikut beberapa fitur inti:

  • Cara yang lebih singkat dan nyaman untuk melakukan tugas sehari-hari
  • Kompatibilitas 100% dengan Streaming JDK asli
  • Keramahan untuk pemrosesan paralel: fitur baru apa pun memanfaatkan streaming paralel sebanyak mungkin
  • Performa dan overhead minimal. Jika StreamEx memungkinkan penyelesaian tugas menggunakan lebih sedikit kode dibandingkan dengan Stream standar , seharusnya tidak lebih lambat secara signifikan dari cara biasa (dan terkadang bahkan lebih cepat)

Dalam tutorial ini, kami akan menyajikan beberapa fitur API StreamEx .

2. Menyiapkan Contoh

Untuk menggunakan StreamEx , kita perlu menambahkan dependensi berikut ke pom.xml :

 one.util streamex 0.6.5 

Versi terbaru perpustakaan dapat ditemukan di Maven Central.

Melalui tutorial ini, kita akan menggunakan kelas User sederhana :

public class User { int id; String name; Role role = new Role(); // standard getters, setters, and constructors }

Dan kelas Peran sederhana :

public class Role { }

3. Metode Jalan Pintas Kolektor

Salah satu operasi terminal Streams yang paling populer adalah operasi kumpulkan ; ini memungkinkan untuk mengemas ulang elemen Stream ke koleksi pilihan kami.

Masalahnya adalah kode bisa menjadi bertele-tele yang tidak perlu untuk skenario sederhana:

users.stream() .map(User::getName) .collect(Collectors.toList());

3.1. Mengumpulkan ke Koleksi

Sekarang, dengan StreamEx, kita tidak perlu menyediakan Collector untuk menentukan bahwa kita membutuhkan List , Set, Map, InmutableList, dll .:

List userNames = StreamEx.of(users) .map(User::getName) .toList();

The collect operasi masih tersedia di API jika kita ingin melakukan sesuatu yang lebih rumit daripada mengambil unsur-unsur dari Streaming dan menempatkan mereka dalam koleksi.

3.2. Kolektor Tingkat Lanjut

Singkatan lainnya adalah groupingBy :

Map
    
      role2users = StreamEx.of(users) .groupingBy(User::getRole);
    

Ini akan menghasilkan Map dengan tipe kunci yang ditentukan dalam referensi metode, menghasilkan sesuatu yang mirip dengan grup dengan operasi di SQL.

Menggunakan API Stream biasa , kita perlu menulis:

Map
    
      role2users = users.stream() .collect(Collectors.groupingBy(User::getRole));
    

Bentuk singkatan yang serupa dapat ditemukan untuk Collectors.joining ():

StreamEx.of(1, 2, 3) .joining("; "); // "1; 2; 3"

Yang mengambil semua elemen di Stream a menghasilkan String yang menggabungkan semuanya.

4. Menambah, Menghapus dan Memilih Elemen

Dalam beberapa skenario, kita punya daftar objek dari tipe yang berbeda, dan kita perlu memfilternya berdasarkan tipe:

List usersAndRoles = Arrays.asList(new User(), new Role()); List roles = StreamEx.of(usersAndRoles) .select(Role.class) .toList();

Kami dapat menambahkan elemen ke awal atau akhir Stream kami , dengan operasi praktis ini:

List appendedUsers = StreamEx.of(users) .map(User::getName) .prepend("(none)") .append("LAST") .toList();

Kita bisa menghapus elemen null yang tidak diinginkan menggunakan nonNull () dan menggunakan Stream sebagai Iterable :

for (String line : StreamEx.of(users).map(User::getName).nonNull()) { System.out.println(line); }

5. Operasi Matematika dan Dukungan Jenis Primitif

StreamEx menambahkan dukungan untuk tipe primitif, seperti yang bisa kita lihat dalam contoh penjelasan mandiri ini:

short[] src = {1,2,3}; char[] output = IntStreamEx.of(src) .map(x -> x * 5) .toCharArray();

Sekarang mari kita ambil array elemen ganda secara tidak berurutan. Kami ingin membuat array yang terdiri dari perbedaan antara setiap pasangan.

Kita dapat menggunakan metode pairMap untuk melakukan operasi ini:

public double[] getDiffBetweenPairs(double... numbers) { return DoubleStreamEx.of(numbers) .pairMap((a, b) -> b - a) .toArray(); }

6. Operasi Peta

6.1. Memfilter berdasarkan Kunci

Fitur berguna lainnya adalah kemampuan untuk membuat Arus dari Peta dan memfilter elemen dengan menggunakan nilai yang mereka tunjuk.

Dalam kasus ini, kami mengambil semua nilai bukan nol:

Map nameToRole = new HashMap(); nameToRole.put("first", new Role()); nameToRole.put("second", null); Set nonNullRoles = StreamEx.ofKeys(nameToRole, Objects::nonNull) .toSet();

6.2. Operating on Key-Value Pairs

We can also operate on key-value pairs by creating an EntryStream instance:

public Map
    
      transformMap( Map
     
       role2users) { Map
      
        users2roles = EntryStream.of(role2users) .flatMapValues(List::stream) .invert() .grouping(); return users2roles; }
      
     
    

The special operation EntryStream.of takes a Map and transforms it into a Stream of key-value objects. Then we use flatMapValues operation to transform our list of roles to a Stream of single values.

Next, we can invert the key-value pair, making the User class the key and the Role class the value.

And finally, we can use the grouping operation to transform our map to the inversion of the one received, all with just four operations.

6.3. Key-Value Mapping

We can also map keys and values independently:

Map mapToString = EntryStream.of(users2roles) .mapKeys(String::valueOf) .mapValues(String::valueOf) .toMap();

With this, we can quickly transform our keys or values to another required type.

7. File Operations

Using StreamEx, we can read files efficiently, i.e., without loading full files at once. It's handy while processing large files:

StreamEx.ofLines(reader) .remove(String::isEmpty) .forEach(System.out::println);

Note that we've used remove() method to filter away empty lines.

Point to note here is that StreamEx won't automatically close the file. Hence, we must remember to manually perform closing operation on both file reading and writing occasion to avoid unnecessary memory overhead.

8. Conclusion

Dalam tutorial ini, kita telah belajar tentang StreamEx , dan kegunaannya yang berbeda. Masih banyak yang harus dilalui - dan mereka memiliki lembar contekan praktis di sini.

Seperti biasa, kode sumber lengkap tersedia di GitHub.