Java Stream所有方法實(shí)例詳解
一、Stream 創(chuàng)建方法
| 方法 | 說(shuō)明 | 示例 |
|---|---|---|
stream() | 從集合創(chuàng)建順序流 | list.stream() |
parallelStream() | 創(chuàng)建并行流 | list.parallelStream() |
Stream.of() | 由一組元素創(chuàng)建流 | Stream.of(1, 2, 3) |
Arrays.stream() | 由數(shù)組創(chuàng)建流 | Arrays.stream(arr) |
Stream.iterate() | 生成無(wú)限流 | Stream.iterate(0, n -> n+2).limit(5) |
Stream.generate() | 生成無(wú)限流 | Stream.generate(Math::random).limit(5) |
二、Stream 中間操作(Intermediate Operations)
這些方法返回新的 Stream,允許鏈?zhǔn)秸{(diào)用。
| 方法 | 說(shuō)明 | 示例 |
|---|---|---|
filter(Predicate) | 過(guò)濾元素 | stream.filter(x -> x > 5) |
map(Function) | 元素映射 | stream.map(x -> x * 2) |
flatMap(Function) | 展開(kāi)嵌套流 | stream.flatMap(list -> list.stream()) |
distinct() | 去重 | stream.distinct() |
sorted() / sorted(Comparator) | 排序 | stream.sorted() / stream.sorted(Comparator.reverseOrder()) |
peek(Consumer) | 元素遍歷但不終止流 | stream.peek(System.out::println) |
limit(long n) | 截取前 n 個(gè)元素 | stream.limit(3) |
skip(long n) | 跳過(guò)前 n 個(gè)元素 | stream.skip(2) |
三、Stream 終止操作(Terminal Operations)
這些方法會(huì)產(chǎn)生結(jié)果或副作用,流被“消費(fèi)”后不可再用。
| 方法 | 說(shuō)明 | 示例 |
|---|---|---|
forEach(Consumer) | 遍歷元素 | stream.forEach(System.out::println) |
collect(Collector) | 收集結(jié)果 | stream.collect(Collectors.toList()) |
toArray() | 轉(zhuǎn)數(shù)組 | stream.toArray() |
reduce(BinaryOperator) | 規(guī)約(聚合) | stream.reduce((a, b) -> a + b) |
count() | 計(jì)數(shù) | stream.count() |
anyMatch(Predicate) | 是否有任意元素匹配 | stream.anyMatch(x -> x > 5) |
allMatch(Predicate) | 是否所有元素都匹配 | stream.allMatch(x -> x > 5) |
noneMatch(Predicate) | 是否沒(méi)有元素匹配 | stream.noneMatch(x -> x > 5) |
findFirst() | 查找第一個(gè)元素 | stream.findFirst() |
findAny() | 查找任意元素 | stream.findAny() |
min(Comparator) | 最小值 | stream.min(Comparator.naturalOrder()) |
max(Comparator) | 最大值 | stream.max(Comparator.naturalOrder()) |
四、常用 Collector 收集器
| 方法 | 說(shuō)明 | 示例 |
|---|---|---|
Collectors.toList() | 轉(zhuǎn) List | stream.collect(Collectors.toList()) |
Collectors.toSet() | 轉(zhuǎn) Set | stream.collect(Collectors.toSet()) |
Collectors.toMap() | 轉(zhuǎn) Map | stream.collect(Collectors.toMap(x -> x, x -> x*2)) |
Collectors.joining() | 字符串拼接 | stream.collect(Collectors.joining(",")) |
Collectors.groupingBy() | 分組 | stream.collect(Collectors.groupingBy(x -> x%2)) |
Collectors.partitioningBy() | 分區(qū) | stream.collect(Collectors.partitioningBy(x -> x > 5)) |
Collectors.counting() | 計(jì)數(shù) | stream.collect(Collectors.counting()) |
Collectors.summingInt() | 求和 | stream.collect(Collectors.summingInt(x -> x)) |
Collectors.averagingInt() | 平均值 | stream.collect(Collectors.averagingInt(x -> x)) |
Collectors.maxBy() | 最大值 | stream.collect(Collectors.maxBy(Comparator.naturalOrder())) |
Collectors.minBy() | 最小值 | stream.collect(Collectors.minBy(Comparator.naturalOrder())) |
五、示例代碼
List<Integer> list = Arrays.asList(1, 2, 3, 4, 5, 6);
// 過(guò)濾、映射、收集
List<Integer> result = list.stream()
.filter(x -> x > 3)
.map(x -> x * 2)
.collect(Collectors.toList()); // [8, 10, 12]
// 分組
Map<Boolean, List<Integer>> partitioned = list.stream()
.collect(Collectors.partitioningBy(x -> x % 2 == 0));
// 計(jì)數(shù)
long count = list.stream().filter(x -> x > 3).count();
// 求和
int sum = list.stream().reduce(0, Integer::sum);六、補(bǔ)充說(shuō)明
- 中間操作是惰性求值,只有終止操作執(zhí)行時(shí)才會(huì)遍歷數(shù)據(jù)。
- Stream 不能被復(fù)用,終止操作后需重新創(chuàng)建流。
- 并行流(parallelStream)適用于大數(shù)據(jù)量,但需注意線程安全和性能。
七、Stream 高級(jí)用法
1. 多級(jí)分組
Map<String, Map<Integer, List<User>>> multiGroup = users.stream()
.collect(Collectors.groupingBy(
User::getCity,
Collectors.groupingBy(User::getAge)
));說(shuō)明:先按城市分組,再按年齡分組,結(jié)果是嵌套的 Map。
2. 分區(qū)與分組的區(qū)別
- 分區(qū):只有兩組(true/false),適合布爾條件。
- 分組:可以有多個(gè)分組鍵。
Map<Boolean, List<Integer>> partition = list.stream()
.collect(Collectors.partitioningBy(x -> x > 3));3. 自定義收集器
可以通過(guò)Collector.of自定義收集邏輯:
Collector<Integer, ?, Set<Integer>> toCustomSet = Collector.of(
HashSet::new,
Set::add,
(left, right) -> { left.addAll(right); return left; }
);
Set<Integer> set = list.stream().collect(toCustomSet);4. 并行流
list.parallelStream()
.filter(x -> x > 3)
.forEach(System.out::println);注意:并行流適合 CPU 密集型任務(wù),IO 密集型需謹(jǐn)慎;操作需線程安全。
5. Optional 結(jié)合 Stream
Optional<Integer> first = list.stream().filter(x -> x > 3).findFirst(); first.ifPresent(System.out::println);
八、常見(jiàn)陷阱與注意點(diǎn)
- 流只能用一次
- 流操作后已關(guān)閉,不能再操作,否則拋異常。
- 修改集合元素
- 不建議在流操作中直接修改原集合元素,推薦返回新集合。
- 空指針問(wèn)題
- Stream 操作前應(yīng)確保集合非 null,推薦使用
Optional.ofNullable(list).orElse(Collections.emptyList()).stream()。
- Stream 操作前應(yīng)確保集合非 null,推薦使用
- 性能問(wèn)題
distinct()、sorted()等操作會(huì)增加性能消耗。- 并行流適合數(shù)據(jù)量大且操作無(wú)副作用的場(chǎng)景。
九、部分方法源碼簡(jiǎn)析
1. filter
default Stream<T> filter(Predicate<? super T> predicate) {
Objects.requireNonNull(predicate);
return new ReferencePipeline.StatelessOp<>(this, StreamShape.REFERENCE, StreamOpFlag.NOT_SORTED) {
@Override
Sink<T> opWrapSink(int flags, Sink<T> sink) {
return new Sink.ChainedReference<T, T>(sink) {
@Override
public void accept(T t) {
if (predicate.test(t)) downstream.accept(t);
}
};
}
};
}說(shuō)明:filter 實(shí)際上是對(duì)每個(gè)元素執(zhí)行 Predicate 判斷,符合條件則傳遞到下游。
2. map
default <R> Stream<R> map(Function<? super T, ? extends R> mapper) {
Objects.requireNonNull(mapper);
return new ReferencePipeline.StatelessOp<>(this, StreamShape.REFERENCE, StreamOpFlag.NOT_SORTED) {
@Override
Sink<T> opWrapSink(int flags, Sink<R> sink) {
return new Sink.ChainedReference<T, R>(sink) {
@Override
public void accept(T t) {
downstream.accept(mapper.apply(t));
}
};
}
};
}說(shuō)明:map 通過(guò) Function 映射每個(gè)元素,返回新的流。
十、典型業(yè)務(wù)場(chǎng)景舉例
1. 數(shù)據(jù)去重并排序
List<String> sorted = list.stream()
.distinct()
.sorted()
.collect(Collectors.toList());2. 統(tǒng)計(jì)分組后的最大值
Map<String, Optional<User>> maxAgeByCity = users.stream()
.collect(Collectors.groupingBy(
User::getCity,
Collectors.maxBy(Comparator.comparingInt(User::getAge))
));3. 多字段分組統(tǒng)計(jì)
Map<String, Map<Integer, Long>> groupCount = users.stream()
.collect(Collectors.groupingBy(
User::getCity,
Collectors.groupingBy(User::getAge, Collectors.counting())
));4. 批量字段提取
List<String> names = users.stream()
.map(User::getName)
.collect(Collectors.toList());5. Stream 處理 Map
Map<String, Integer> map = ...;
List<String> keys = map.entrySet().stream()
.filter(e -> e.getValue() > 5)
.map(Map.Entry::getKey)
.collect(Collectors.toList());十一、Stream API 性能建議
- 盡量減少中間操作鏈長(zhǎng)度,必要時(shí)合并操作。
- 大數(shù)據(jù)量推薦并行流,但需測(cè)試線程安全和實(shí)際效率。
- 優(yōu)先使用基本類(lèi)型流(IntStream、LongStream、DoubleStream)可減少裝箱/拆箱開(kāi)銷(xiāo)。
- 避免在流中寫(xiě)復(fù)雜邏輯,建議拆分為多個(gè)方法提高可讀性。
十二、Stream 相關(guān)擴(kuò)展
- IntStream/LongStream/DoubleStream:針對(duì)基本類(lèi)型的流,效率更高。
- Collectors.toConcurrentMap:并發(fā)收集器,適合并行流。
- Collectors.mapping:在分組或分區(qū)時(shí)對(duì)元素做映射。
- Collectors.reducing:自定義規(guī)約操作。
十三、基本類(lèi)型流詳解
Java 提供了三種基本類(lèi)型流,分別是 IntStream、LongStream 和 DoubleStream,它們避免了自動(dòng)裝箱/拆箱,提高了性能。
創(chuàng)建方式
IntStream intStream = IntStream.of(1, 2, 3, 4); LongStream longStream = LongStream.range(1, 10); // [1,9] DoubleStream doubleStream = DoubleStream.generate(Math::random).limit(5);
常用方法
| 方法 | 說(shuō)明 | 示例 |
|---|---|---|
sum() | 求和 | intStream.sum() |
average() | 平均值 | intStream.average().getAsDouble() |
max() / min() | 最大/最小值 | intStream.max().getAsInt() |
boxed() | 轉(zhuǎn)換為對(duì)象流 | intStream.boxed() |
mapToObj() | 基本類(lèi)型流轉(zhuǎn)對(duì)象流 | intStream.mapToObj(String::valueOf) |
十四、流的收集與轉(zhuǎn)換技巧
1. 轉(zhuǎn)換為 Map,處理 key 重復(fù)
// value 相加
Map<String, Integer> map = list.stream()
.collect(Collectors.toMap(
User::getName,
User::getScore,
Integer::sum // 合并函數(shù)
));2. 收集為不可變集合
List<String> unmodifiableList = list.stream()
.collect(Collectors.collectingAndThen(
Collectors.toList(),
Collections::unmodifiableList
));3. 多字段分組
Map<String, Map<Integer, List<User>>> group = users.stream()
.collect(Collectors.groupingBy(
User::getCity,
Collectors.groupingBy(User::getAge)
));十五、Stream 與并發(fā)/線程安全
- 并行流:
parallelStream()會(huì)自動(dòng)分片并行處理,適合無(wú)狀態(tài)、無(wú)副作用的操作。 - 線程安全收集:使用
Collectors.toConcurrentMap、ConcurrentHashMap等。
ConcurrentMap<String, Integer> concurrentMap = list.parallelStream()
.collect(Collectors.toConcurrentMap(User::getName, User::getScore));十六、Stream 排序技巧
1. 單字段排序
list.stream()
.sorted(Comparator.comparing(User::getAge))
.collect(Collectors.toList());2. 多字段排序
list.stream()
.sorted(Comparator.comparing(User::getAge)
.thenComparing(User::getName))
.collect(Collectors.toList());3. 逆序排序
list.stream()
.sorted(Comparator.comparing(User::getAge).reversed())
.collect(Collectors.toList());十七、Stream 實(shí)用代碼片段
1. 找出重復(fù)元素
Set<Integer> seen = new HashSet<>();
Set<Integer> duplicates = list.stream()
.filter(n -> !seen.add(n))
.collect(Collectors.toSet());2. 分頁(yè)功能
int page = 2, size = 5;
List<Integer> pageList = list.stream()
.skip((page - 1) * size)
.limit(size)
.collect(Collectors.toList());3. 按條件統(tǒng)計(jì)數(shù)量
long count = list.stream().filter(x -> x > 10).count();
4. 合并兩個(gè) List 并去重
List<Integer> merged = Stream.concat(list1.stream(), list2.stream())
.distinct()
.collect(Collectors.toList());十八、常見(jiàn)問(wèn)題與解決方案
1. Stream 只用一次
Stream<String> s = list.stream(); s.forEach(System.out::println); // s.forEach(...) // 拋異常,不可再用
解決:重新創(chuàng)建流。
2. NullPointerException
集合為 null 時(shí)不能直接調(diào)用 stream()。
List<String> safeList = Optional.ofNullable(list)
.orElse(Collections.emptyList());
safeList.stream()...3. 性能瓶頸
- 避免在流操作中寫(xiě)復(fù)雜邏輯,拆分方法。
- 并行流適合數(shù)據(jù)量大且操作無(wú)副作用,需實(shí)際測(cè)試。
十九、Collectors 的擴(kuò)展用法
1. mapping
分組后對(duì)分組內(nèi)元素做映射:
Map<String, List<String>> nameGroup = users.stream()
.collect(Collectors.groupingBy(
User::getCity,
Collectors.mapping(User::getName, Collectors.toList())
));2. reducing
自定義聚合:
int totalScore = users.stream()
.collect(Collectors.reducing(0, User::getScore, Integer::sum));二十、Stream 處理嵌套集合
List<List<Integer>> nested = Arrays.asList(
Arrays.asList(1,2),
Arrays.asList(3,4)
);
List<Integer> flat = nested.stream()
.flatMap(Collection::stream)
.collect(Collectors.toList());二十一、Stream API 新增方法(Java 9+)
如果你用的是 Java 9 及以上,還可以用:
takeWhile(Predicate):從頭開(kāi)始,遇到不滿足條件就停止。dropWhile(Predicate):從頭開(kāi)始,遇到不滿足條件后開(kāi)始收集。Stream.ofNullable(obj):對(duì)象為 null 返回空流,否則返回單元素流。
Stream.ofNullable(null).count(); // 0
Stream.ofNullable("abc").count(); // 1二十二、Stream 與 Lambda 表達(dá)式最佳實(shí)踐
- 保持流操作簡(jiǎn)潔,避免嵌套 lambda 過(guò)多。
- 推薦將復(fù)雜邏輯提取為方法引用或單獨(dú)方法。
- 用注釋說(shuō)明復(fù)雜的流鏈。
總結(jié)
Java Stream 提供了豐富的 API,適合處理集合的各種操作,包括過(guò)濾、映射、分組、聚合、排序、去重等。掌握 Stream 可以極大提升 Java 代碼的簡(jiǎn)潔性和表現(xiàn)力。
到此這篇關(guān)于Java Stream所有方法實(shí)例詳解的文章就介紹到這了,更多相關(guān)Java Stream所有方法內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
SpringBoot如何指定某些類(lèi)優(yōu)先啟動(dòng)
這篇文章主要介紹了SpringBoot如何指定某些類(lèi)優(yōu)先啟動(dòng),文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下2019-09-09
java的Object里wait()實(shí)現(xiàn)原理講解
這篇文章主要介紹了java的Object里wait()實(shí)現(xiàn)原理,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2021-09-09
IDEA無(wú)法識(shí)別SpringBoot項(xiàng)目的簡(jiǎn)單解決辦法
今天使用idea的時(shí)候,遇到idea無(wú)法啟動(dòng)springboot,所以這篇文章主要給大家介紹了關(guān)于IDEA無(wú)法識(shí)別SpringBoot項(xiàng)目的簡(jiǎn)單解決辦法,需要的朋友可以參考下2023-08-08
SpringBoot AOP處理請(qǐng)求日志打印功能代碼實(shí)例
這篇文章主要介紹了SpringBoot AOP處理請(qǐng)求日志打印功能代碼實(shí)例,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下2020-03-03
SpringMVC配置攔截器實(shí)現(xiàn)登錄控制的方法
這篇文章主要介紹了SpringMVC配置攔截器實(shí)現(xiàn)登錄控制的方法,SpringMVC讀取Cookie判斷用戶是否登錄,對(duì)每一個(gè)action都要進(jìn)行判斷,有興趣的可以了解一下。2017-03-03
教你怎么用idea創(chuàng)建web項(xiàng)目
好多朋友在使用IDEA創(chuàng)建項(xiàng)目時(shí),總會(huì)碰到一些小問(wèn)題.現(xiàn)在我們就演示一下使用IDEA創(chuàng)建web項(xiàng)目的完整步驟吧.文中有非常詳細(xì)的圖文示例哦,,需要的朋友可以參考下2021-05-05
解析Spring Boot 如何讓你的 bean 在其他 bean&n
在 SpringBoot 中如何讓自己的某個(gè)指定的 Bean 在其他 Bean 前完成被 Spring 加載?我聽(tīng)到這個(gè)問(wèn)題的第一反應(yīng)是,為什么會(huì)有這樣奇怪的需求?下面小編給大家分析下Spring Boot 如何讓你的 bean 在其他 bean 之前完成加載 ,感興趣的朋友一起看看吧2024-01-01
SpringBoot模塊多項(xiàng)目解耦的最佳實(shí)踐
為了提高代碼質(zhì)量和靈活性,在Spring Boot項(xiàng)目中采用策略模式是一個(gè)有效的方法,該模式允許定義一系列算法并將每一個(gè)封裝起來(lái),使它們可以互相替換,本文給大家介紹了SpringBoot模塊多項(xiàng)目解耦的最佳實(shí)踐,需要的朋友可以參考下2025-02-02

