Java Streams:初學者的指南
你好,未來的Java大師!今天,我們將要踏上一段令人興奮的旅程,進入Java Streams的世界。如果你是編程新手,別擔心——我將成為你的友好指南,我們會一步步來。在本教程結束時,你將能像專家一樣流式處理數據!
Java中的Stream是什麼?
想像你在一個傳送帶壽司餐廳。壽司盤不斷地在你面前移動,你可以挑選你想要的。這就是Java中Stream的本質——它是一個元素的序列,你可以一個接一個地處理,而不必將它們全部存儲在記憶體中。
Streams在Java 8中引入,以使處理數據集合更為輕鬆和高效。它們讓我們能以更具說明性的方式對數據進行操作,告訴Java我們想做什麼,而不是如何做。
在Java中生成Streams
讓我們從創建我們的第一個Stream開始。有幾種方法可以做到這點,但我們從一個簡單的例子開始:
import java.util.Arrays;
import java.util.List;
import java.util.stream.Stream;
public class StreamExample {
public static void main(String[] args) {
// 從List創建Stream
List<String> fruits = Arrays.asList("apple", "banana", "cherry", "date");
Stream<String> fruitStream = fruits.stream();
// 直接創建Stream
Stream<Integer> numberStream = Stream.of(1, 2, 3, 4, 5);
}
}
在這個例子中,我們創建了兩個Streams。第一個,fruitStream
,是從水果列表創建的。第二個,numberStream
,是使用Stream.of()
方法直接創建的。
常見的Stream操作
現在有了我們的Streams,讓我們看看一些我們可以對它們進行的常見操作。
forEach方法
forEach
方法就像一個友好的機器人,它會遍歷Stream中的每個元素並對其進行操作。讓我們用它來打印我們的水果:
fruits.stream().forEach(fruit -> System.out.println(fruit));
這將打印:
apple
banana
cherry
date
在這裡,fruit -> System.out.println(fruit)
被稱為lambda表達式。它是一種告訴Java對每個元素做什麼的簡潔方式。
map方法
map
方法就像一根魔杖,它可以轉換Stream中的每個元素。讓我們用它將我們的所有水果轉換為大寫:
List<String> upperCaseFruits = fruits.stream()
.map(String::toUpperCase)
.collect(Collectors.toList());
System.out.println(upperCaseFruits);
這將打印:
[APPLE, BANANA, CHERRY, DATE]
String::toUpperCase
是一個方法引用,這是Java的另一個便捷特性,就像說“對每個String使用toUpperCase方法”。
filter方法
filter
方法就像俱樂部的保鏢,只讓某些元素通過。讓我們用它來保留以'a'開頭的水果:
List<String> aFruits = fruits.stream()
.filter(fruit -> fruit.startsWith("a"))
.collect(Collectors.toList());
System.out.println(aFruits);
這將打印:
[apple]
limit方法
limit
方法就像說“我只想要這麼多,謝謝!”它限制了Stream中的元素數量:
List<String> firstTwoFruits = fruits.stream()
.limit(2)
.collect(Collectors.toList());
System.out.println(firstTwoFruits);
這將打印:
[apple, banana]
sorted方法
sorted
方法就像整理你的書架。它將元素按照順序排列:
List<String> sortedFruits = fruits.stream()
.sorted()
.collect(Collectors.toList());
System.out.println(sortedFruits);
這將打印:
[apple, banana, cherry, date]
並行處理
關於Streams的一個很酷的事情是,它們可以很容易地進行並行處理,從而有潛在地在大型數據集上加速操作。你可以這樣創建一個並行Stream:
fruits.parallelStream().forEach(fruit -> System.out.println(fruit + " " + Thread.currentThread().getName()));
這可能會打印像這樣的東西:
banana ForkJoinPool.commonPool-worker-1
apple main
date ForkJoinPool.commonPool-worker-2
cherry ForkJoinPool.commonPool-worker-3
每次你運行它時,順序可能會不同,因為水果正在被並行處理!
Collectors
Collectors是特殊工具,它們幫助我們收集Stream操作的結果。我們在例子中一直在使用collect(Collectors.toList())
將我們的Stream結果轉換回Lists。還有許多其他有用的Collectors:
// 將元素連接成字符串
String fruitString = fruits.stream().collect(Collectors.joining(", "));
System.out.println(fruitString); // 打印: apple, banana, cherry, date
// 計數元素
long fruitCount = fruits.stream().collect(Collectors.counting());
System.out.println(fruitCount); // 打印: 4
// 組織元素
Map<Character, List<String>> fruitGroups = fruits.stream()
.collect(Collectors.groupingBy(fruit -> fruit.charAt(0)));
System.out.println(fruitGroups); // 打印: {a=[apple], b=[banana], c=[cherry], d=[date]}
統計
Streams還可以幫助我們對數字數據計算統計:
List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5);
IntSummaryStatistics stats = numbers.stream().mapToInt(Integer::intValue).summaryStatistics();
System.out.println("Count: " + stats.getCount());
System.out.println("Sum: " + stats.getSum());
System.out.println("Min: " + stats.getMin());
System.out.println("Max: " + stats.getMax());
System.out.println("Average: " + stats.getAverage());
這將打印:
Count: 5
Sum: 15
Min: 1
Max: 5
Average: 3.0
Java Streams範例
讓我們將所有這些東西結合起來,創造一個更複雜的例子。想像我們有一個學生列表,他們的年齡和成績如下:
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> students = 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)
);
// 獲得21歲以上學生的平均成績
double averageGrade = students.stream()
.filter(student -> student.age > 21)
.mapToDouble(student -> student.grade)
.average()
.orElse(0.0);
System.out.println("21歲以上學生的平均成績: " + averageGrade);
// 獲得成績最高的兩名學生的名字
List<String> topStudents = students.stream()
.sorted((s1, s2) -> Double.compare(s2.grade, s1.grade))
.limit(2)
.map(student -> student.name)
.collect(Collectors.toList());
System.out.println("成績最高的兩名學生: " + topStudents);
}
}
這個例子展示了我們如何將多個Stream操作串聯起來,以簡潔且易於閱讀的方式執行複雜的數據處理任務。
那就是它,夥伴們!你剛剛踏入了Java Streams的世界。記住,熟能生巧,所以不要害怕嘗試這些概念。在你意識到之前,你將會像專家一樣流式處理數據!快樂編程!
Credits: Image by storyset