Panduan Pemula untuk Java Streams

Hai sana, para ahli Java masa depan! Hari ini, kita akan memulai perjalanan menarik ke dunia Java Streams. Jangan khawatir jika Anda baru belajar programming - saya akan menjadi panduan Anda, dan kita akan mengambil langkah ini satu per satu. Pada akhir panduan ini, Anda akan bisa mengolah data seperti seorang pro!

Java - Streams

Apa Itu Stream di Java?

Bayangkan Anda di restoran sushi dengan konveyor. Piring sushi terus bergerak di depan Anda, dan Anda dapat memilih apa yang Anda inginkan. Itu sebenarnya seperti apa sebuah Stream di Java - itu adalah urutan elemen yang Anda dapat proses satu per satu, tanpa perlu menyimpan semuanya di memori sekaligus.

Streams diperkenalkan di Java 8 untuk membuat kerja dengan koleksi data menjadi mudah dan efisien. Mereka memungkinkan kita untuk melakukan operasi pada data dalam cara yang lebih deklaratif, mengatakan pada Java apa yang kita inginkan untuk dilakukan daripada bagaimana cara melakukannya.

Membuat Streams di Java

mari kita mulai dengan membuat Stream pertama kita. Ada beberapa cara untuk melakukan ini, tapi kita akan mulai dengan contoh sederhana:

import java.util.Arrays;
import java.util.List;
import java.util.stream.Stream;

public class StreamExample {
public static void main(String[] args) {
// Membuat Stream dari List
List<String> buah = Arrays.asList("apple", "banana", "cherry", "date");
Stream<String> streamBuah = buah.stream();

// Membuat Stream secara langsung
Stream<Integer> streamNomor = Stream.of(1, 2, 3, 4, 5);
}
}

Dalam contoh ini, kita telah membuat dua Streams. Yang pertama, streamBuah, dibuat dari List buah. Yang kedua, streamNomor, dibuat langsung menggunakan metode Stream.of().

Operasi Stream Umum

Sekarang kita memiliki Streams, mari kita lihat beberapa operasi umum yang dapat kita lakukan pada mereka.

Metode forEach

Metode forEach mirip dengan robot ramah yang melewati setiap elemen di Stream dan melakukan sesuatu dengannya. mari kita gunakan itu untuk mencetak buah-buahan kita:

buah.stream().forEach(buah -> System.out.println(buah));

Ini akan mencetak:

apple
banana
cherry
date

Di sini, buah -> System.out.println(buah) disebut ekspresi lambda. Itu adalah cara singkat untuk memberitahu Java apa yang harus dilakukan dengan setiap elemen.

Metode map

Metode map mirip dengan tongkat sihir yang mengubah setiap elemen di Stream. mari kita gunakan itu untuk membuat semua buah kapital:

List<String> buahKapital = buah.stream()
.map(String::toUpperCase)
.collect(Collectors.toList());
System.out.println(buahKapital);

Ini akan mencetak:

[APPLE, BANANA, CHERRY, DATE]

String::toUpperCase adalah referensi metode, fitur keren lainnya di Java yang mirip dengan mengatakan "gunakan metode toUpperCase pada setiap String".

Metode filter

Metode filter mirip dengan penjaga klub yang hanya membiarkan elemen tertentu melewati. mari kita gunakan itu untuk hanya menjaga buah yang dimulai dengan huruf 'a':

List<String> buahA = buah.stream()
.filter(buah -> buah.startsWith("a"))
.collect(Collectors.toList());
System.out.println(buahA);

Ini akan mencetak:

[apple]

Metode limit

Metode limit mirip dengan mengatakan "Saya hanya ingin ini banyak, terima kasih!" Itu membatasi Stream ke jumlah elemen tertentu:

List<String> duaBuahPertama = buah.stream()
.limit(2)
.collect(Collectors.toList());
System.out.println(duaBuahPertama);

Ini akan mencetak:

[apple, banana]

Metode sorted

Metode sorted mirip dengan mengatur rak buku Anda. Itu mengurutkan elemen:

List<String> buahTerurut = buah.stream()
.sorted()
.collect(Collectors.toList());
System.out.println(buahTerurut);

Ini akan mencetak:

[apple, banana, cherry, date]

Pemrosesan Paralel

Salah satu hal menarik tentang Streams adalah mereka dapat mudah diproses paralel, secara potensial mempercepat operasi pada dataset besar. Anda dapat membuat Stream paralel seperti ini:

buah.parallelStream().forEach(buah -> System.out.println(buah + " " + Thread.currentThread().getName()));

Ini mungkin mencetak sesuatu seperti ini:

banana ForkJoinPool.commonPool-worker-1
apple main
date ForkJoinPool.commonPool-worker-2
cherry ForkJoinPool.commonPool-worker-3

Urutan mungkin berbeda setiap kali Anda menjalankan itu, karena buah-buahan diproses secara paralel!

Collectors

Collectors adalah alat khusus yang membantu kita mengumpulkan hasil operasi Stream. Kita telah menggunakan collect(Collectors.toList()) dalam contoh kita untuk mengubah hasil Stream kita kembali ke List. Ada banyak Collectors lain yang berguna:

// Menggabungkan elemen menjadi String
String stringBuah = buah.stream().collect(Collectors.joining(", "));
System.out.println(stringBuah);  // Mencetak: apple, banana, cherry, date

// Menghitung elemen
long jumlahBuah = buah.stream().collect(Collectors.counting());
System.out.println(jumlahBuah);  // Mencetak: 4

// Mengelompokkan elemen
Map<Character, List<String>> kelompokBuah = buah.stream()
.collect(Collectors.groupingBy(buah -> buah.charAt(0)));
System.out.println(kelompokBuah);  // Mencetak: {a=[apple], b=[banana], c=[cherry], d=[date]}

Statistik

Streams juga dapat membantu kita menghitung statistik pada data numerik:

List<Integer> nomor = Arrays.asList(1, 2, 3, 4, 5);
IntSummaryStatistics stats = nomor.stream().mapToInt(Integer::intValue).summaryStatistics();
System.out.println("Jumlah: " + stats.getCount());
System.out.println("Jumlah: " + stats.getSum());
System.out.println("Minimum: " + stats.getMin());
System.out.println("Maksimum: " + stats.getMax());
System.out.println("Rata-rata: " + stats.getAverage());

Ini akan mencetak:

Jumlah: 5
Jumlah: 15
Minimum: 1
Maksimum: 5
Rata-rata: 3.0

Contoh Java Streams

mari kita gabungkan semuanya dengan contoh yang lebih kompleks. Bayangkan kita memiliki daftar siswa dengan umur dan nilai mereka:

class Student {
String name;
int age;
double grade;

Student(String name, int age, double grade) {
this.name = name;
this.age = age;
this.grade = grade;
}
}

public class StreamExample {
public static void main(String[] args) {
List<Student> siswa = Arrays.asList(
new Student("Alice", 22, 90.5),
new Student("Bob", 20, 85.0),
new Student("Charlie", 21, 92.3),
new Student("David", 23, 88.7)
);

// Mendapatkan rata-rata nilai siswa di atas 21
double rataRataNilai = siswa.stream()
.filter(siswa -> siswa.age > 21)
.mapToDouble(siswa -> siswa.grade)
.average()
.orElse(0.0);

System.out.println("Rata-rata nilai siswa di atas 21: " + rataRataNilai);

// Mendapatkan nama siswa terbaik 2 berdasarkan nilai
List<String> siswaTerbaik = siswa.stream()
.sorted((s1, s2) -> Double.compare(s2.grade, s1.grade))
.limit(2)
.map(siswa -> siswa.name)
.collect(Collectors.toList());

System.out.println("2 siswa terbaik: " + siswaTerbaik);
}
}

Contoh ini menunjukkan bagaimana kita dapat menggabungkan beberapa operasi Stream untuk melakukan tugas pemrosesan data yang kompleks dalam cara yang ringkas dan dapat dibaca.

Dan itu saja, teman-teman! Anda telah mengambil langkah pertama ke dunia Java Streams. Ingat, latihan membuat sempurna, jadi jangan khawatir untuk mencoba konsep ini. Sebelum Anda tahu, Anda akan bisa mengolah data seperti seorang pro! Selamat coding!

Credits: Image by storyset