1. Daftar metode Stream
kelas
Kelas Stream
dibuat untuk memudahkan pembuatan rantai aliran data. Untuk mencapai ini, Stream<T>
kelas memiliki metode yang mengembalikan Stream
objek baru.
Masing-masing aliran data ini melakukan satu tindakan sederhana, tetapi jika Anda menggabungkannya menjadi rantai dan menambahkan fungsi lambda yang menarik , Anda memiliki mekanisme yang kuat untuk menghasilkan keluaran yang Anda inginkan. Segera Anda akan melihat sendiri.
Berikut adalah metode kelas Stream
(hanya yang paling dasar):
Metode | Keterangan |
---|---|
|
Membuat aliran dari sekumpulan objek |
|
Menghasilkan aliran sesuai dengan aturan yang ditentukan |
|
Menggabungkan dua aliran |
|
Memfilter data, hanya meneruskan data yang cocok dengan aturan yang ditentukan |
|
Menghapus duplikat. Tidak meneruskan data yang sudah ditemui |
|
Mengurutkan data |
|
Melakukan tindakan pada setiap elemen dalam aliran |
|
Mengembalikan aliran yang terpotong sehingga tidak lebih dari batas yang ditentukan |
|
Melewati n elemen pertama |
|
Mengonversi data dari satu jenis ke jenis lainnya |
|
Mengonversi data dari satu jenis ke jenis lainnya |
|
Memeriksa apakah setidaknya ada satu elemen dalam aliran yang cocok dengan aturan yang ditentukan |
|
Memeriksa apakah semua elemen dalam aliran cocok dengan aturan yang ditentukan |
|
Memeriksa apakah tidak ada elemen dalam aliran yang cocok dengan aturan yang ditentukan |
|
Mengembalikan elemen pertama yang ditemukan cocok dengan aturan |
|
Mengembalikan elemen apa pun dalam aliran yang cocok dengan aturan |
|
Mencari elemen minimum dalam aliran data |
|
Mengembalikan elemen maksimum dalam aliran data |
|
Mengembalikan jumlah elemen dalam aliran data |
|
Membaca semua data dari aliran dan mengembalikannya sebagai koleksi |
2. Operasi perantara dan terminal oleh Stream
kelas
Seperti yang Anda lihat, tidak semua metode dalam tabel di atas mengembalikan a Stream
. Ini terkait dengan fakta bahwa metode kelas Stream
dapat dibagi menjadi metode perantara (juga dikenal sebagai non-terminal ) dan metode terminal .
Metode menengah
Metode perantara mengembalikan objek yang mengimplementasikan antarmuka Stream
, dan mereka dapat dirangkai bersama.
Metode terminal
Metode terminal mengembalikan nilai selain a Stream
.
Saluran pemanggilan metode
Dengan demikian, Anda dapat membangun aliran pipa yang terdiri dari sejumlah metode perantara dan panggilan metode terminal tunggal di bagian akhir. Pendekatan ini memungkinkan Anda menerapkan logika yang agak rumit, sekaligus meningkatkan keterbacaan kode.
Data di dalam aliran data tidak berubah sama sekali. Rantai metode perantara adalah cara apik (deklaratif) untuk menentukan pipa pemrosesan data yang akan dieksekusi setelah metode terminal dipanggil.
Dengan kata lain, jika metode terminal tidak dipanggil, maka data dalam aliran data tidak diproses dengan cara apa pun. Hanya setelah metode terminal dipanggil, data mulai diproses sesuai dengan aturan yang ditentukan dalam aliran pipa.
stream()
.intemediateOperation1()
.intemediateOperation2()
...
.intemediateOperationN()
.terminalOperation();
Perbandingan metode perantara dan terminal:
intermediat | terminal | |
---|---|---|
Jenis pengembalian | Stream |
tidak aStream |
Dapat dikombinasikan dengan beberapa metode dari jenis yang sama untuk membentuk saluran pipa | Ya | TIDAK |
Jumlah metode dalam satu pipeline | setiap | tidak lebih dari satu |
Menghasilkan hasil akhir | TIDAK | Ya |
Mulai memproses data dalam aliran | TIDAK | Ya |
Mari kita lihat sebuah contoh.
Misalkan kita memiliki klub pecinta binatang. Besok klub merayakan Hari Kucing Jahe. Klub memiliki pemilik hewan peliharaan, yang masing-masing memiliki daftar hewan peliharaan. Mereka tidak terbatas pada kucing.
Tugas: Anda perlu mengidentifikasi semua nama semua kucing jahe untuk membuat kartu ucapan yang dipersonalisasi untuk mereka untuk "liburan profesional" besok. Kartu ucapan harus diurutkan berdasarkan usia kucing, dari yang tertua hingga yang termuda.
Pertama, kami menyediakan beberapa kelas untuk membantu menyelesaikan tugas ini:
public enum Color {
WHITE,
BLACK,
DARK_GREY,
LIGHT_GREY,
FOXY,
GREEN,
YELLOW,
BLUE,
MAGENTA
}
public abstract class Animal {
private String name;
private Color color;
private int age;
public Animal(String name, Color color, int age) {
this.name = name;
this.color = color;
this.age = age;
}
public String getName() {
return name;
}
public Color getColor() {
return color;
}
public int getAge() {
return age;
}
}
public class Cat extends Animal {
public Cat(String name, Color color, int age) {
super(name, color, age);
}
}
public class Dog extends Animal {
public Dog(String name, Color color, int age) {
super(name, color, age);
}
}
public class Parrot extends Animal {
public Parrot(String name, Color color, int age) {
super(name, color, age);
}
}
public class Pig extends Animal {
public Pig(String name, Color color, int age) {
super(name, color, age);
}
}
public class Snake extends Animal {
public Snake(String name, Color color, int age) {
super(name, color, age);
}
}
public class Owner {
private String name;
private List<Animal> pets = new ArrayList<>();
public Owner(String name) {
this.name = name;
}
public List<Animal> getPets() {
return pets;
}
}
Sekarang mari kita lihat kelasnya Selector
, di mana pemilihan akan dilakukan sesuai dengan kriteria yang ditentukan:
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
public class Selector {
private static List<Owner> owners;
private static void initData() {
final Owner owner1 = new Owner("Ronan Turner");
owner1.getPets().addAll(List.of(
new Cat("Baron", Color.BLACK, 3),
new Cat("Sultan", Color.DARK_GREY, 4),
new Dog("Elsa", Color.WHITE, 0)
));
final Owner owner2 = new Owner("Scarlet Murray");
owner2.getPets().addAll(List.of(
new Cat("Ginger", Color.FOXY, 7),
new Cat("Oscar", Color.FOXY, 5),
new Parrot("Admiral", Color.BLUE, 3)
));
final Owner owner3 = new Owner("Felicity Mason");
owner3.getPets().addAll(List.of(
new Dog("Arnold", Color.FOXY, 3),
new Pig("Vacuum Cleaner", Color.LIGHT_GREY, 8)
));
final Owner owner4 = new Owner("Mitchell Stone");
owner4.getPets().addAll(List.of(
new Snake("Mr. Boa", Color.DARK_GREY, 2)
));
final Owner owner5 = new Owner("Jonathan Snyder");
owner5.getPets().addAll(List.of(
new Cat("Fisher", Color.BLACK, 16),
new Cat("Zorro", Color.FOXY, 14),
new Cat("Margo", Color.WHITE, 3),
new Cat("Brawler", Color.DARK_GREY, 1)
));
owners = List.of(owner1, owner2, owner3, owner4, owner5);
}
}
Yang tersisa adalah menambahkan kode ke main
metode. Saat ini, pertama-tama kita memanggil initData()
metode yang mengisi daftar pemilik hewan peliharaan di klub. Kemudian kami memilih nama kucing jahe yang diurutkan berdasarkan usianya dalam urutan menurun.
Pertama, mari kita lihat kode yang tidak menggunakan stream untuk menyelesaikan tugas ini:
public static void main(String[] args) {
initData();
List<String> findNames = new ArrayList<>();
List<Cat> findCats = new ArrayList<>();
for (Owner owner : owners) {
for (Animal pet : owner.getPets()) {
if (Cat.class.equals(pet.getClass()) && Color.FOXY == pet.getColor()) {
findCats.add((Cat) pet);
}
}
}
Collections.sort(findCats, new Comparator<Cat>() {
public int compare(Cat o1, Cat o2) {
return o2.getAge() - o1.getAge();
}
});
for (Cat cat : findCats) {
findNames.add(cat.getName());
}
findNames.forEach(System.out::println);
}
Sekarang mari kita lihat alternatifnya:
public static void main(String[] args) {
initData();
final List<String> findNames = owners.stream()
.flatMap(owner -> owner.getPets().stream())
.filter(pet -> Cat.class.equals(pet.getClass()))
.filter(cat -> Color.FOXY == cat.getColor())
.sorted((o1, o2) -> o2.getAge() - o1.getAge())
.map(Animal::getName)
.collect(Collectors.toList());
findNames.forEach(System.out::println);
}
Seperti yang Anda lihat, kodenya jauh lebih ringkas. Selain itu, setiap baris pipa aliran adalah satu tindakan, sehingga dapat dibaca seperti kalimat dalam bahasa Inggris:
|
Pindah dari a Stream<Owner> ke aStream<Pet> |
|
Pertahankan hanya kucing di aliran data |
|
Pertahankan hanya jahe kucing di aliran data |
|
Urutkan berdasarkan usia dalam urutan menurun |
|
Dapatkan namanya |
|
Masukkan hasilnya ke dalam daftar |
3. Membuat aliran
Kelas Stream
memiliki tiga metode yang belum kita bahas. Tujuan dari ketiga metode ini adalah untuk membuat utas baru.
Stream<T>.of(T obj)
metode
Metode ini of()
membuat aliran yang terdiri dari satu elemen. Ini biasanya diperlukan ketika, katakanlah, suatu fungsi mengambil Stream<T>
objek sebagai argumen, tetapi Anda hanya memiliki T
objek. Kemudian Anda dapat dengan mudah dan sederhana menggunakan of()
metode tersebut untuk mendapatkan aliran yang terdiri dari satu elemen .
Contoh:
Stream<Integer> stream = Stream.of(1);
Stream<T> Stream.of(T obj1, T obj2, T obj3, ...)
metode
Metode ini of()
membuat aliran yang terdiri dari elemen yang diteruskan . Sejumlah elemen diperbolehkan. Contoh:
Stream<Integer> stream = Stream.of(1, 2, 3, 4, 5);
Stream<T> Stream.generate(Supplier<T> obj)
metode
Metode ini generate()
memungkinkan Anda menetapkan aturan yang akan digunakan untuk menghasilkan elemen aliran berikutnya saat diminta. Misalnya, Anda dapat memberikan nomor acak setiap kali.
Contoh:
Stream<Double> s = Stream.generate(Math::random);
Stream<T> Stream.concat(Stream<T> a, Stream<T> b)
metode
Metode ini concat()
menggabungkan dua aliran yang diteruskan menjadi satu . Saat data dibaca, pertama kali dibaca dari aliran pertama, lalu dari aliran kedua. Contoh:
Stream<Integer> stream1 = Stream.of(1, 2, 3, 4, 5);
Stream<Integer> stream2 = Stream.of(10, 11, 12, 13, 14);
Stream<Integer> result = Stream.concat(stream1, stream2);
4. Memfilter data
6 metode lainnya membuat aliran data baru, memungkinkan Anda menggabungkan aliran menjadi rantai (atau saluran pipa) dengan berbagai kompleksitas.
Stream<T> filter(Predicate<T>)
metode
Metode ini mengembalikan aliran data baru yang memfilter aliran data sumber sesuai dengan aturan yang diteruskan . Metode harus dipanggil pada objek yang bertipe Stream<T>
.
Anda dapat menentukan aturan pemfilteran menggunakan fungsi lambda , yang kemudian akan dikonversi oleh kompiler menjadi Predicate<T>
objek.
Contoh:
Aliran yang dirantai | Penjelasan |
---|---|
|
Pertahankan hanya angka kurang dari tiga |
|
Pertahankan hanya angka yang lebih besar dari nol |
Stream<T> sorted(Comparator<T>)
metode
Metode ini mengembalikan aliran data baru yang mengurutkan data dalam aliran sumber . Anda memasukkan komparator , yang menetapkan aturan untuk membandingkan dua elemen aliran data.
Stream<T> distinct()
metode
Metode ini mengembalikan aliran data baru yang hanya berisi elemen unik dalam aliran data sumber . Semua data duplikat dibuang. Contoh:
Stream<Integer> stream = Stream.of(1, 2, 3, 4, 5, 2, 2, 2, 3, 4);
Stream<Integer> stream2 = stream.distinct(); // 1, 2, 3, 4, 5
Stream<T> peek(Consumer<T>)
metode
Metode ini mengembalikan aliran data baru , meskipun data di dalamnya sama dengan aliran sumber. Tetapi ketika elemen berikutnya diminta dari aliran, fungsi yang Anda berikan ke peek()
metode dipanggil dengannya.
Jika Anda meneruskan fungsi System.out::println
ke peek()
metode, maka semua objek akan ditampilkan saat melewati aliran.
Stream<T> limit(int n)
metode
Metode ini mengembalikan aliran data baru yang hanya berisi n
elemen pertama dalam aliran data sumber . Semua data lainnya dibuang. Contoh:
Stream<Integer> stream = Stream.of(1, 2, 3, 4, 5, 2, 2, 2, 3, 4);
Stream<Integer> stream2 = stream.limit(3); // 1, 2, 3
Stream<T> skip(int n)
metode
Metode ini mengembalikan aliran data baru yang berisi semua elemen yang sama dengan aliran sumber , tetapi melewatkan (mengabaikan) elemen pertama n
. Contoh:
Stream<Integer> stream = Stream.of(1, 2, 3, 4, 5, 2, 2, 2, 3, 4);
Stream<Integer> stream2 = stream.skip(3); // 4, 5, 2, 2, 2, 3, 4
GO TO FULL VERSION