Aliran Java 8: Pendekatan Deklaratif untuk Pemrosesan Data
Stream adalah lapisan abstrak baru yang diperkenalkan dalam Java 8. Dengan menggunakan stream, Anda dapat memproses data dengan cara deklaratif yang mirip dengan pernyataan SQL. Sebagai contoh, pertimbangkan pernyataan SQL berikut.
SELECT max(salary), employee_id, employee_name FROM Employee
Pernyataan SQL di atas secara otomatis mengembalikan detail karyawan dengan gaji tertinggi, tanpa melakukan komputasi apa pun di sisi pengembang. Menggunakan kerangka koleksi dalam Java, seorang pengembang harus menggunakan loop dan melakukan pemeriksaan berulang. Kekhawatiran lain adalah efisiensi; karena prosesor multi-core tersedia dengan mudah, seorang pengembang Java harus menulis pemrosesan kode paralel yang dapat cukup rawan kesalahan.
Untuk mengatasi masalah ini, Java 8 memperkenalkan konsep stream yang memungkinkan pengembang untuk memproses data secara deklaratif dan memanfaatkan arsitektur multi-core tanpa perlu menulis kode spesifik untuk itu.
Apa itu Stream?
Stream mewakili urutan objek dari sumber, yang mendukung operasi agregat. Berikut adalah karakteristik sebuah Stream −
Urutan elemen − Sebuah stream menyediakan seperangkat elemen dari tipe tertentu secara berurutan. Sebuah stream mendapatkan/mengkomputasi elemen sesuai permintaan. Ia tidak pernah menyimpan elemen.
Sumber − Stream mengambil Koleksi, Array, atau sumber daya I/O sebagai sumber masukan.
Operasi agregat − Stream mendukung operasi agregat seperti filter, map, limit, reduce, find, match, dan sebagainya.
Pipelining − Kebanyakan operasi stream mengembalikan stream itu sendiri sehingga hasilnya dapat dipipelinekan. Operasi ini disebut operasi intermediate dan fungsinya adalah mengambil masukan, memprosesnya, dan mengembalikan keluaran ke target. Metode collect() adalah operasi terminal yang biasanya ada di akhir operasi pipelining untuk menandai akhir stream.
Iterasi otomatis − Operasi stream melakukan iterasi secara internal atas elemen sumber yang diberikan, berbeda dengan Koleksi di mana iterasi eksplisit diperlukan.
Menghasilkan Stream
Dengan Java 8, antarmuka Collection memiliki dua metode untuk menghasilkan Stream.
List<String> strings = Arrays.asList("abc", "", "bc", "efg", "abcd","", "jkl"); List<String> filtered = strings.stream().filter(string -> !string.isEmpty()).collect(Collectors.toList()); forEach
Stream telah menyediakan metode baru ‘forEach’ untuk mengulangi setiap elemen dari stream. Cuplikan kode berikut menunjukkan cara mencetak 10 angka acak menggunakan forEach.
Random random = new Random(); random.ints().limit(10).forEach(System.out::println);
map
Metode ‘map’ digunakan untuk memetakan setiap elemen ke hasil yang sesuai. Cuplikan kode berikut mencetak kuadrat unik dari angka menggunakan map.
List<Integer> numbers = Arrays.asList(3, 2, 2, 3, 7, 3, 5); //get list of unique squares List<Integer> squaresList = numbers.stream().map( i -> i*i).distinct().collect(Collectors.toList());
filter
Metode ‘filter’ digunakan untuk menghilangkan elemen berdasarkan kriteria. Cuplikan kode berikut mencetak jumlah string kosong menggunakan filter.
List<String>strings = Arrays.asList("abc", "", "bc", "efg", "abcd","", "jkl"); //get count of empty string int count = strings.stream().filter(string -> string.isEmpty()).count(); limit
Metode ‘limit’ digunakan untuk mengurangi ukuran stream. Cuplikan kode berikut menunjukkan cara mencetak 10 angka acak menggunakan limit.
Random random = new Random(); random.ints().limit(10).forEach(System.out::println);
sorted
Metode ‘sorted’ digunakan untuk mengurutkan stream. Cuplikan kode berikut menunjukkan cara mencetak 10 angka acak dalam urutan yang diurutkan.
Random random = new Random(); random.ints().limit(10).sorted().forEach(System.out::println);
Parallel Processing
parallelStream adalah alternatif stream untuk pemrosesan paralel. Lihat cuplikan kode berikut yang mencetak jumlah string kosong menggunakan parallelStream.
List<String> strings = Arrays.asList("abc", "", "bc", "efg", "abcd","", "jkl"); //get count of empty string long count = strings.parallelStream().filter(string -> string.isEmpty()).count(); Sangat mudah untuk beralih antara stream berurutan dan paralel.
Collectors
Collectors digunakan untuk menggabungkan hasil pemrosesan pada elemen dari stream. Collectors dapat digunakan untuk mengembalikan daftar atau string.
List<String>strings = Arrays.asList("abc", "", "bc", "efg", "abcd","", "jkl"); List<String> filtered = strings.stream().filter(string -> !string.isEmpty()).collect(Collectors.toList()); System.out.println("Filtered List: " + filtered); String mergedString = strings.stream().filter(string -> !string.isEmpty()).collect(Collectors.joining(", ")); System.out.println("Merged String: " + mergedString); Statistics
Dengan Java 8, pengumpan statistik diperkenalkan untuk menghitung semua statistik saat pemrosesan stream dilakukan.
List numbers = Arrays.asList(3, 2, 2, 3, 7, 3, 5); IntSummaryStatistics stats = numbers.stream().mapToInt((x) -> x).summaryStatistics(); System.out.println("Highest number in List : " + stats.getMax()); System.out.println("Lowest number in List : " + stats.getMin()); System.out.println("Sum of all numbers : " + stats.getSum()); System.out.println("Average of all numbers : " + stats.getAverage()); Contoh Stream
Buat program Java berikut menggunakan editor pilihan Anda, katakanlah di C:\> JAVA.
Java8Tester.java
Live Demo
import java.util.ArrayList; import java.util.Arrays; import java.util.IntSummaryStatistics; import java.util.List; import java.util.Random; import java.util.stream.Collectors; import java.util.Map; public class Java8Tester { public static void main(String args[]) { System.out.println("Using Java 7: "); // Count empty strings List<String> strings = Arrays.asList("abc", "", "bc", "efg", "abcd","", "jkl"); System.out.println("List: " +strings); long count = getCountEmptyStringUsingJava7(strings); System.out.println("Empty Strings: " + count); count = getCountLength3UsingJava7(strings); System.out.println("Strings of length 3: " + count); //Eliminate empty string List<String> filtered = deleteEmptyStringsUsingJava7(strings); System.out.println("Filtered List: " + filtered); //Eliminate empty string and join using comma. String mergedString = getMergedStringUsingJava7(strings,", "); System.out.println("Merged String: " + mergedString); List<Integer> numbers = Arrays.asList(3, 2, 2, 3, 7, 3, 5); //get list of square of distinct numbers List<Integer> squaresList = getSquares(numbers); System.out.println("Squares List: " + squaresList); List<Integer> integers = Arrays.asList(1,2,13,4,15,6,17,8,19); System.out.println("List: " +integers); System.out.println("Highest number in List : " + getMax(integers)); System.out.println("Lowest number in List : " + getMin(integers)); System.out.println("Sum of all numbers : " + getSum(integers)); System.out.println("Average of all numbers : " + getAverage(integers)); System.out.println("Random Numbers: "); //print ten random numbers Random random = new Random(); for(int i = 0; i < 10; i++) { System.out.println(random.nextInt()); } System.out.println("Using Java 8: "); System.out.println("List: " +strings); count = strings.stream().filter(string->string.isEmpty()).count(); System.out.println("Empty Strings: " + count); count = strings.stream().filter(string -> string.length() == 3).count(); System.out.println("Strings of length 3: " + count); filtered = strings.stream().filter(string ->!string.isEmpty()).collect(Collectors.toList()); System.out.println("Filtered List: " + filtered); mergedString = strings.stream().filter(string ->!string.isEmpty()).collect(Collectors.joining(", ")); System.out.println("Merged String: " + mergedString); squaresList = numbers.stream().map( i ->i*i).distinct().collect(Collectors.toList()); System.out.println("Squares List: " + squaresList); System.out.println("List: " +integers); IntSummaryStatistics stats = integers.stream().mapToInt((x) ->x).summaryStatistics(); System.out.println("Highest number in List : " + stats.getMax()); System.out.println("Lowest number in List : " + stats.getMin()); System.out.println("Sum of all numbers : " + stats.getSum()); System.out.println("Average of all numbers : " + stats.getAverage()); System.out.println("Random Numbers: "); random.ints().limit(10).sorted().forEach(System.out::println); //parallel processing count = strings.parallelStream().filter(string -> string.isEmpty()).count(); System.out.println("Empty Strings: " + count); } private static int getCountEmptyStringUsingJava7(List<String> strings) { int count = 0; for(String string: strings) { if(string.isEmpty()) { count++; } } return count; } private static int getCountLength3UsingJava7(List<String> strings) { int count = 0; for(String string: strings) { if(string.length() == 3) { count++; } } return count; } private static List<String> deleteEmptyStringsUsingJava7(List<String> strings) { List<String> filteredList = new ArrayList<String>(); for(String string: strings) { if(!string.isEmpty()) { filteredList.add(string); } } return filteredList; } private static String getMergedStringUsingJava7(List<String> strings, String separator) { StringBuilder stringBuilder = new StringBuilder(); for(String string: strings) { if(!string.isEmpty()) { stringBuilder.append(string); stringBuilder.append(separator); } } String mergedString = stringBuilder.toString(); return mergedString.substring(0, mergedString.length()-2); } private static List<Integer> getSquares(List<Integer> numbers) { List<Integer> squaresList = new ArrayList<Integer>(); for(Integer number: numbers) { Integer square = new Integer(number.intValue() * number.intValue()); if(!squaresList.contains(square)) { squaresList.add(square); } } return squaresList; } private static int getMax(List<Integer> numbers) { int max = numbers.get(0); for(int i = 1;i < numbers.size();i++) { Integer number = numbers.get(i); if(number.intValue() > max) { max = number.intValue(); } } return max; } private static int getMin(List<Integer> numbers) { int min = numbers.get(0); for(int i= 1;i < numbers.size();i++) { Integer number = numbers.get(i); if(number.intValue() < min) { min = number.intValue(); } } return min; } private static int getSum(List numbers) { int sum = (int)(numbers.get(0)); for(int i = 1;i < numbers.size();i++) { sum += (int)numbers.get(i); } return sum; } private static int getAverage(List<Integer> numbers) { return getSum(numbers) / numbers.size(); } } Verifikasi Hasil
Kompilasi kelas menggunakan compiler javac seperti berikut −
C:\JAVA>javac Java8Tester.java
Sekarang jalankan Java8Tester seperti berikut −
C:\JAVA>java Java8Tester
Hasilnya akan seperti berikut −
Using Java 7: List: [abc, , bc, efg, abcd, , jkl] Empty Strings: 2 Strings of length 3: 3 Filtered List: [abc, bc, efg, abcd, jkl] Merged String: abc, bc, efg, abcd, jkl Squares List: [9, 4, 49, 25] List: [1, 2, 13, 4, 15, 6, 17, 8, 19] Highest number in List : 19 Lowest number in List : 1 Sum of all numbers : 85 Average of all numbers : 9 Random Numbers: -1279735475 903418352 -1133928044 -1571118911 628530462 18407523 -881538250 -718932165 270259229 421676854 Using Java 8: List: [abc, , bc, efg, abcd, , jkl] Empty Strings: 2 Strings of length 3: 3 Filtered List: [abc, bc, efg, abcd, jkl] Merged String: abc, bc, efg, abcd, jkl Squares List: [9, 4, 49, 25] List: [1, 2, 13, 4, 15, 6, 17, 8, 19] Highest number in List : 19 Lowest number in List : 1 Sum of all numbers : 85 Average of all numbers : 9.444444444444445 Random Numbers: -1009474951 -551240647 -2484714 181614550 933444268 1227850416 1579250773 1627454872 1683033687 1798939493 Empty Strings: 2