一、一句话总结
Stream = 数据流管道,支持函数式操作,可链式调用,延迟执行,用于高效处理集合数据
二、核心概念
数据源 → 创建Stream → 中间操作(过滤/映射) → 终端操作(收集/计算)
↑ ↑ ↑
stream() filter/map/sorted collect/count
三、创建Stream
1. 从集合创建
// 1. Collection接口的stream()方法
List<String> list = Arrays.asList("A", "B", "C");
Stream<String> stream1 = list.stream(); // 顺序流
Stream<String> parallelStream = list.parallelStream(); // 并行流
// 2. 数组创建
String[] array = {"A", "B", "C"};
Stream<String> stream2 = Arrays.stream(array);
Stream<String> stream3 = Stream.of(array);
Stream<String> stream4 = Stream.of("A", "B", "C");
2. 其他方式创建
// 3. 无限流
Stream<Integer> infinite1 = Stream.iterate(0, n -> n + 1); // 0,1,2,3...
Stream<Double> infinite2 = Stream.generate(Math::random); // 随机数流
// 4. 范围流
IntStream range1 = IntStream.range(1, 5); // 1,2,3,4 (不包括5)
IntStream range2 = IntStream.rangeClosed(1, 5); // 1,2,3,4,5
// 5. 空流
Stream<String> emptyStream = Stream.empty();
四、中间操作(返回新Stream)
1. 筛选过滤
List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5, 6);
// filter - 过滤
List<Integer> even = numbers.stream()
.filter(n -> n % 2 == 0) // 保留偶数
.collect(Collectors.toList()); // [2, 4, 6]
// distinct - 去重
List<Integer> distinct = Arrays.asList(1, 2, 2, 3, 3, 3).stream()
.distinct() // 去重
.collect(Collectors.toList()); // [1, 2, 3]
// limit - 限制数量
List<Integer> first3 = numbers.stream()
.limit(3) // 取前3个
.collect(Collectors.toList()); // [1, 2, 3]
// skip - 跳过前N个
List<Integer> skip2 = numbers.stream()
.skip(2) // 跳过前2个
.collect(Collectors.toList()); // [3, 4, 5, 6]
2. 映射转换
List<String> words = Arrays.asList("hello", "world");
// map - 一对一转换
List<Integer> lengths = words.stream()
.map(String::length) // String → Integer
.collect(Collectors.toList()); // [5, 5]
List<String> upper = words.stream()
.map(String::toUpperCase) // 转大写
.collect(Collectors.toList()); // [HELLO, WORLD]
// flatMap - 一对多展开
List<List<String>> listOfLists = Arrays.asList(
Arrays.asList("a", "b"),
Arrays.asList("c", "d")
);
List<String> flattened = listOfLists.stream()
.flatMap(List::stream) // 展开为单个流
.collect(Collectors.toList()); // [a, b, c, d]
3. 排序
List<String> names = Arrays.asList("Tom", "Jerry", "Alice", "Bob");
// 自然排序
List<String> sorted = names.stream()
.sorted() // 自然顺序
.collect(Collectors.toList()); // [Alice, Bob, Jerry, Tom]
// 自定义排序
List<String> customSorted = names.stream()
.sorted(Comparator.reverseOrder()) // 逆序
.collect(Collectors.toList()); // [Tom, Jerry, Bob, Alice]
// 多条件排序
List<Person> people = Arrays.asList(
new Person("Alice", 25),
new Person("Bob", 30),
new Person("Alice", 20)
);
List<Person> sortedPeople = people.stream()
.sorted(Comparator
.comparing(Person::getName)
.thenComparing(Person::getAge)) // 先按姓名,再按年龄
.collect(Collectors.toList());
五、终端操作(返回结果)
1. 收集结果
List<String> names = Arrays.asList("Alice", "Bob", "Charlie");
// 收集为List
List<String> list = names.stream()
.filter(n -> n.length() > 3)
.collect(Collectors.toList()); // [Alice, Charlie]
// 收集为Set(自动去重)
Set<String> set = names.stream()
.collect(Collectors.toSet());
// 收集为Map
Map<String, Integer> map = names.stream()
.collect(Collectors.toMap(
name -> name, // key
String::length // value
)); // {Alice=5, Bob=3, Charlie=7}
// 连接字符串
String joined = names.stream()
.collect(Collectors.joining(", ")); // "Alice, Bob, Charlie"
2. 统计计算
List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5);
// 计数
long count = numbers.stream().count(); // 5
// 求和
int sum = numbers.stream()
.mapToInt(Integer::intValue)
.sum(); // 15
// 平均值
OptionalDouble avg = numbers.stream()
.mapToInt(Integer::intValue)
.average(); // OptionalDouble[3.0]
// 最大值/最小值
Optional<Integer> max = numbers.stream()
.max(Integer::compare); // Optional[5]
Optional<Integer> min = numbers.stream()
.min(Integer::compare); // Optional[1]
// 归约(reduce)
Optional<Integer> sumReduce = numbers.stream()
.reduce((a, b) -> a + b); // Optional[15]
Integer sumWithInit = numbers.stream()
.reduce(0, (a, b) -> a + b); // 15(有初始值)
3. 匹配查找
List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5);
// 是否存在满足条件的元素
boolean anyEven = numbers.stream()
.anyMatch(n -> n % 2 == 0); // true(存在偶数)
// 是否所有元素都满足条件
boolean allPositive = numbers.stream()
.allMatch(n -> n > 0); // true(都大于0)
// 是否没有元素满足条件
boolean noneNegative = numbers.stream()
.noneMatch(n -> n < 0); // true(没有负数)
// 查找第一个
Optional<Integer> firstEven = numbers.stream()
.filter(n -> n % 2 == 0)
.findFirst(); // Optional[2]
// 查找任意一个(并行流中效率更高)
Optional<Integer> anyEven2 = numbers.parallelStream()
.filter(n -> n % 2 == 0)
.findAny(); // 任意一个偶数
六、分组和分区
1. 分组
List<Person> people = Arrays.asList(
new Person("Alice", 25, "IT"),
new Person("Bob", 30, "HR"),
new Person("Charlie", 25, "IT"),
new Person("David", 35, "HR")
);
// 按部门分组
Map<String, List<Person>> byDept = people.stream()
.collect(Collectors.groupingBy(Person::getDepartment));
// {IT=[Alice, Charlie], HR=[Bob, David]}
// 分组后统计
Map<String, Long> countByDept = people.stream()
.collect(Collectors.groupingBy(
Person::getDepartment,
Collectors.counting()
)); // {IT=2, HR=2}
// 多级分组
Map<String, Map<Integer, List<Person>>> nestedGroup = people.stream()
.collect(Collectors.groupingBy(
Person::getDepartment,
Collectors.groupingBy(Person::getAge)
));
2. 分区
List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5, 6);
// 按条件分为true/false两组
Map<Boolean, List<Integer>> partitioned = numbers.stream()
.collect(Collectors.partitioningBy(n -> n % 2 == 0));
// {false=[1, 3, 5], true=[2, 4, 6]}
七、并行流
1. 创建并行流
List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5, 6, 7, 8, 9, 10);
// 方法1:从集合创建
Stream<Integer> parallelStream = numbers.parallelStream();
// 方法2:转换顺序流为并行流
Stream<Integer> parallel = numbers.stream().parallel();
// 方法3:转换并行流为顺序流
Stream<Integer> sequential = parallelStream.sequential();
2. 并行流注意事项
// 适合并行的情况:大数据量、计算密集、无状态操作
long sum = numbers.parallelStream()
.mapToLong(Integer::longValue)
.sum();
// 不适合并行的情况:
// 1. 有状态操作(sorted可能有问题)
// 2. 操作顺序重要时
// 3. 数据量太小(并行开销可能更大)
八、实际应用示例
1. 数据处理管道
public class StreamExamples {
// 示例1:统计单词频率
public Map<String, Long> wordFrequency(String text) {
return Arrays.stream(text.toLowerCase().split("\\W+"))
.filter(word -> !word.isEmpty())
.collect(Collectors.groupingBy(
word -> word,
Collectors.counting()
));
}
// 示例2:查询员工信息
public List<Employee> findTopPaidEmployees(List<Employee> employees, int limit) {
return employees.stream()
.filter(e -> e.getDepartment().equals("IT"))
.sorted(Comparator.comparing(Employee::getSalary).reversed())
.limit(limit)
.collect(Collectors.toList());
}
// 示例3:计算交易统计
public TransactionStats analyzeTransactions(List<Transaction> transactions) {
DoubleSummaryStatistics stats = transactions.stream()
.mapToDouble(Transaction::getAmount)
.summaryStatistics();
return new TransactionStats(
stats.getCount(),
stats.getSum(),
stats.getAverage(),
stats.getMax(),
stats.getMin()
);
}
}
2. 复杂数据转换
// 从订单列表生成报表
public class OrderReporter {
public Report generateReport(List<Order> orders) {
// 按用户分组,计算每个用户的订单总金额
Map<String, Double> userTotal = orders.stream()
.collect(Collectors.groupingBy(
Order::getUserId,
Collectors.summingDouble(Order::getTotalAmount)
));
// 找出金额最高的订单
Optional<Order> highestOrder = orders.stream()
.max(Comparator.comparing(Order::getTotalAmount));
// 按日期统计每日订单数
Map<LocalDate, Long> dailyCount = orders.stream()
.collect(Collectors.groupingBy(
Order::getOrderDate,
Collectors.counting()
));
return new Report(userTotal, highestOrder, dailyCount);
}
}
九、性能优化技巧
1. 短路操作
List<String> names = Arrays.asList("Alice", "Bob", "Charlie");
// 找到第一个长度大于5的名字后就停止
Optional<String> result = names.stream()
.filter(name -> {
System.out.println("检查: " + name);
return name.length() > 5;
})
.findFirst(); // 只检查到Charlie就会停止
// 使用limit减少处理量
List<Integer> top3 = IntStream.range(1, 1000000)
.filter(n -> n % 2 == 0)
.limit(3) // 只取前3个,避免处理全部
.boxed()
.collect(Collectors.toList());
2. 避免装箱拆箱
// ❌ 不好:频繁装箱拆箱
List<Integer> numbers = IntStream.range(1, 1000)
.boxed() // 装箱
.filter(n -> n % 2 == 0)
.mapToInt(Integer::intValue) // 拆箱
.sum();
// ✅ 好:使用原始类型流
int sum = IntStream.range(1, 1000)
.filter(n -> n % 2 == 0) // 没有装箱拆箱
.sum();
十、常见陷阱
1. 流只能消费一次
Stream<String> stream = Stream.of("A", "B", "C");
// 第一次消费
stream.forEach(System.out::println); // 正常输出
// 第二次消费会报错
// stream.forEach(System.out::println); // 抛出IllegalStateException
// 解决方案:重新创建流
Stream<String> newStream = Stream.of("A", "B", "C");
newStream.forEach(System.out::println);
2. 并行流的线程安全
// ❌ 线程不安全
List<Integer> result = new ArrayList<>();
IntStream.range(0, 1000).parallel()
.forEach(result::add); // 可能丢失数据或抛出异常
// ✅ 线程安全
List<Integer> safeResult = IntStream.range(0, 1000).parallel()
.boxed()
.collect(Collectors.toList());
总结要点
核心特性:
- 链式调用:
.stream().filter().map().collect() - 延迟执行:只有终端操作才会真正执行
- 不可复用:流只能消费一次
- 并行处理:
.parallelStream()轻松并行
常用操作:
- 中间操作:filter, map, sorted, distinct, limit, skip
- 终端操作:collect, forEach, reduce, count, anyMatch
- 收集器:Collectors.toList(), groupingBy(), joining()
选择指南:
- 小数据量用顺序流
- 大数据量、计算密集用并行流
- 需要原始类型时用IntStream/LongStream/DoubleStream
- 多次使用相同数据时重新创建流