Java 8 引入的 Stream API 是處理集合數據的強大工具,它允許你以聲明式方式處理數據集合,支持各種聚合操作和并行處理。以下是 Stream API 的核心知識點及具體代碼示例:
1. Stream 概述
Stream 是數據渠道,用于操作數據源(如集合、數組)所生成的元素序列。注意:
- Stream 自己不會存儲元素。
- Stream 不會改變源對象,相反,它們會返回一個持有結果的新 Stream。
- Stream 操作是延遲執行的,這意味著它們會等到需要結果時才執行。
2. Stream 的創建
可以通過集合、數組、靜態方法等創建 Stream。
import java.util.*;
import java.util.stream.*;public class StreamCreation {public static void main(String[] args) {// 1. 通過 Collection 接口的 stream() 或 parallelStream() 方法List<String> list = Arrays.asList("apple", "banana", "cherry");Stream<String> streamFromList = list.stream(); // 順序流Stream<String> parallelStream = list.parallelStream(); // 并行流// 2. 通過 Arrays 類的 stream() 方法Integer[] array = {1, 2, 3, 4, 5};Stream<Integer> streamFromArray = Arrays.stream(array);// 3. 通過 Stream 類的靜態方法:of()、iterate()、generate()Stream<String> streamOf = Stream.of("a", "b", "c");Stream<Integer> streamIterate = Stream.iterate(0, n -> n + 2).limit(5); // 0, 2, 4, 6, 8Stream<Double> streamGenerate = Stream.generate(Math::random).limit(3);// 4. 創建空 StreamStream<String> emptyStream = Stream.empty();}
}
3. Stream 的中間操作
中間操作會返回一個新的 Stream,多個中間操作可以連接成一個流水線。常用操作:
- 過濾:
filter(Predicate<T>)
- 映射:
map(Function<T, R>)
、flatMap(Function<T, Stream<R>>)
- 排序:
sorted()
、sorted(Comparator<T>)
- 去重:
distinct()
- 截斷:
limit(long maxSize)
- 跳過:
skip(long n)
import java.util.Arrays;
import java.util.List;
import java.util.stream.Stream;public class StreamIntermediateOperations {public static void main(String[] args) {List<String> words = Arrays.asList("hello", "world", "java", "stream");// 過濾長度大于4的單詞,并轉為大寫,最后排序Stream<String> result = words.stream().filter(word -> word.length() > 4) // 過濾長度>4的單詞.map(String::toUpperCase) // 轉為大寫.sorted(); // 自然排序result.forEach(System.out::println); // 輸出: HELLO, WORLD, STREAM}
}
4. Stream 的終止操作
終止操作會觸發流水線的執行并產生結果。常用操作:
- 遍歷:
forEach(Consumer<T>)
- 匹配:
allMatch()
、anyMatch()
、noneMatch()
- 查找:
findFirst()
、findAny()
- 歸約:
reduce()
- 收集:
collect()
- 統計:
count()
、max()
、min()
import java.util.*;
import java.util.stream.Collectors;public class StreamTerminalOperations {public static void main(String[] args) {List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5, 6, 7, 8, 9, 10);// 1. 匹配與查找boolean allEven = numbers.stream().allMatch(n -> n % 2 == 0); // falseboolean anyEven = numbers.stream().anyMatch(n -> n % 2 == 0); // trueOptional<Integer> firstEven = numbers.stream().filter(n -> n % 2 == 0).findFirst(); // 2// 2. 歸約:計算總和int sum = numbers.stream().reduce(0, Integer::sum); // 55// 3. 收集:轉為集合或統計List<Integer> evenNumbers = numbers.stream().filter(n -> n % 2 == 0).collect(Collectors.toList()); // [2, 4, 6, 8, 10]// 4. 分組:按奇偶分組Map<Boolean, List<Integer>> groupedByEven = numbers.stream().collect(Collectors.partitioningBy(n -> n % 2 == 0));// 5. 統計IntSummaryStatistics stats = numbers.stream().mapToInt(Integer::intValue).summaryStatistics();System.out.println("Count: " + stats.getCount()); // 10System.out.println("Sum: " + stats.getSum()); // 55System.out.println("Average: " + stats.getAverage()); // 5.5}
}
5. 并行流與串行流
- 串行流:單線程處理流中的元素。
- 并行流:內部使用 Fork/Join 框架多線程并行處理(適合大數據量)。
import java.util.Arrays;
import java.util.List;public class ParallelStreamExample {public static void main(String[] args) {List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5);// 串行流(單線程)numbers.stream().map(n -> {System.out.println(Thread.currentThread().getName() + ": " + n);return n * 2;}).forEach(System.out::println);System.out.println("---");// 并行流(多線程)numbers.parallelStream().map(n -> {System.out.println(Thread.currentThread().getName() + ": " + n);return n * 2;}).forEach(System.out::println);}
}
6. Stream 的惰性求值
中間操作不會立即執行,只有遇到終止操作時才會觸發執行。
import java.util.Arrays;
import java.util.List;public class StreamLaziness {public static void main(String[] args) {List<String> names = Arrays.asList("Alice", "Bob", "Charlie", "David");// 中間操作不會執行names.stream().filter(name -> {System.out.println("Filtering: " + name);return name.length() > 4;}).map(name -> {System.out.println("Mapping: " + name);return name.toUpperCase();});// 沒有終止操作,不會輸出任何內容// 添加終止操作后觸發執行names.stream().filter(name -> {System.out.println("Filtering: " + name);return name.length() > 4;}).map(name -> {System.out.println("Mapping: " + name);return name.toUpperCase();}).forEach(System.out::println);}
}
總結
Stream API 的核心流程:創建 Stream → 中間操作(過濾、映射等)→ 終止操作(收集結果)。合理使用 Stream 可以讓代碼更簡潔、更具可讀性,同時利用并行流提升大數據處理效率。