| 特性 | 說明 |
| 不存儲數據 | 基於數據源(集合、陣列、IO)透過管道傳遞元素 |
| 函數式 | 操作不修改源,filter 不刪除原集合元素 |
| 延遲執行 | 中間操作(filter/map)僅記錄,終端操作才真正執行 |
| 可短路 | limit/findFirst 遇無限流也能在有限步完成 |
| 單次消費 | 元素只能遍歷一次,需重新獲取 Stream 再用 |
創建 Stream 的 8 種方式
Collection.stream() / parallelStream()
Arrays.stream(T[]) / Arrays.stream(int[])
- 靜態工廠:
Stream.of()、IntStream.range()、Stream.iterate()、Stream.generate()
BufferedReader.lines() 文件行流
Files.list/find/walk 路徑流
Random.ints() 隨機數流
- 第三方:
BitSet.stream()、Pattern.splitAsStream()、JarFile.stream()
- 底層:
StreamSupport.stream(Spliterator)
中間操作
| 操作 | 說明 | 示例 |
distinct() | 去重(equals) | Stream.of("a","b","a").distinct() → [a,b] |
filter(Predicate) | 篩選符合條件元素 | IntStream.range(1,10).filter(i->i%2==0) → [2,4,6,8] |
map(Function) | 一對一轉換,可改類型 | Stream.of('a','b').map(c->c.hashCode()) → [97,98] |
flatMap(Function) | 一對多扁平化 | lines.flatMap(line->Arrays.stream(line.split(" "))) |
limit(n) | 截取前 n 個 | IntStream.range(1,100).limit(5) → [1..5] |
peek(Consumer) | 消費但不改變流(調試用) | .peek(System.out::println) |
sorted() / sorted(Comparator) | 排序 | .sorted((a,b)->a-b) |
skip(n) | 跳過前 n 個 | .skip(3) |
終端操作
| 分類 | 操作 | 說明 |
| 匹配 | allMatch/anyMatch/noneMatch | 斷言全滿足/任一滿足/全不滿足,空流 allMatch=true, anyMatch=false, noneMatch=true |
count() | 元素個數(實現為 mapToLong(e->1L).sum()) |
findFirst() / findAny() | 返回首個/任一元素(Optional),並行流 findAny 更快但結果不確定 |
| 遍歷 | forEach(Consumer) | 不保證順序,有序流用 forEachOrdered |
forEachOrdered | 保證遇見順序執行 |
| 極值 | max(Comparator) / min(Comparator) | 返回 Optional |
| 歸約 | reduce | 三種重載:無初值/有初值/並行專用 combiner,累加器需滿足結合律 |
| 收集 | collect(Collector) | 最強終端操作,見下節收集器詳解 |
| 轉陣列 | toArray() | 返回 Object[] 或類型陣列 |
收集器:Collectors 工具類精華
// 轉集合
.toList() / .toSet() / .toCollection(ArrayList::new)
// 字串連接
.joining() / .joining(",") / .joining(",", "[", "]")
// 分組 / 分區
.groupingBy(User::getDept)
.groupingBy(User::getDept, counting())
.partitioningBy(user -> user.getAge() > 18)
// 聚合
.counting() / .summingInt(User::getAge) / .averagingDouble(User::getScore)
.maxBy(Comparator.comparing(User::getAge)) / .minBy(...)
.summarizingInt(User::getAge) // 返回 IntSummaryStatistics
// 降級/轉換
.mapping(User::getName, toList())
.collectingAndThen(toList(), Collections::unmodifiableList)
// 自定義 Collector
Collector.of(supplier, accumulator, combiner, finisher, characteristics)
並行流與性能
- 默認串行,
parallelStream() 或 .parallel() 開啟。
- 無狀態、非干擾、關聯性滿足時,並行結果與串行一致。
- 有序流並行可能降低性能(
distinct、sorted、limit),可 .unordered() 優化。
- 小數據量、高計算密度任務適合並行;IO 密集、大量同步鎖反而變慢。
常見陷阱
- 重複消費:
stream.forEach(...); stream.count(); → IllegalStateException,需重新獲取流。
- 修改源集合:終端操作執行期間修改非併發集合 →
ConcurrentModificationException。
- 有狀態 Lambda:並行下結果不確定,保持純函數。
- 副作用濫用:
forEach(list::add) 非線程安全,改用 collect(toList())。
- 裝箱開銷:基本類型流(
IntStream)避免裝箱,性能提升明顯。
第三方擴展推薦
- protonpack:
takeWhile、zip、unfold、MapStream 等缺失操作。
- java8-utils:實用輔助方法補充。
總結
Stream API 讓集合處理從「怎麼做」轉向「做什麼」,配合 Lambda 與收集器,代碼更簡潔、可讀、易並行。掌握中間/終端操作分類、收集器組合、並行適用場景與常見坑,是現代 Java 開發必備技能。
- 上一篇文章: Java AES 加密解密實戰:跨平台一致、支援中文、Base64 輸出
- 下一篇文章: Eclipse 效率神器:10 大必知快捷鍵與進階技巧全集
Copyright ©
程式碼之家 All Rights Reserved