Java Stream 流完全指南
Stream 是 Java 8 引入的一种处理集合数据的强大抽象,它允许我们以声明式方式处理数据集合,而不是通过循环迭代。下面详细介绍 Stream 的使用方法、功能及实际应用场景。
一、Stream 基础概念
1.1 什么是 Stream
Stream 是一个支持顺序和并行聚合操作的元素序列。它不是数据结构,而是一种在数据集合上进行复杂操作的抽象视图。
1.2 Stream 操作分类
中间操作:返回新的 Stream,可以链接多个操作(延迟执行)
终端操作:触发流的计算,生成结果或副作用
二、创建 Stream
2.1 从集合创建
// 从 List 创建
List<String> list = Arrays.asList("a", "b", "c");
Stream<String> stream = list.stream();
// 从 Set 创建
Set<String> set = new HashSet<>(Arrays.asList("a", "b", "c"));
Stream<String> stream = set.stream();
// 从 Map 创建
Map<String, Integer> map = new HashMap<>();
map.put("a", 1);
map.put("b", 2);
Stream<Map.Entry<String, Integer>> stream = map.entrySet().stream();
扩展:
map.entrySet()是一种便捷遍历访问map中元素的方法,方法返回一个 Set,其中包含了 Map 中的所有键值对。每个键值对由 Map.Entry 表示。
2.2 从数组创建
String[] arr = {"a", "b", "c"};
Stream<String> stream = Arrays.stream(arr);
2.3 其他创建方式
// 使用 Stream.of
Stream<String> stream = Stream.of("a", "b", "c");
// 创建空流
Stream<String> emptyStream = Stream.empty();
// 创建无限流
Stream<Integer> infiniteStream = Stream.iterate(0, n -> n + 2); // 偶数流
Stream<Double> randomStream = Stream.generate(Math::random); // 随机数流
三、常用中间操作
3.1 filter - 过滤元素
// 功能:保留满足条件的元素
Stream<T> filter(Predicate<? super T> predicate)
使用场景:筛选满足特定条件的数据
// 示例:筛选成年用户
List<User> adults = userList.stream()
.filter(user -> user.getAge() >= 18)
.collect(Collectors.toList());
3.2 map - 元素映射转换
// 功能:将元素转换为其他形式
<R> Stream<R> map(Function<? super T, ? extends R> mapper)
使用场景:提取对象中的特定属性,或进行数据转换
// 示例:提取用户名列表
List<String> userNames = userList.stream()
.map(User::getName)
.collect(Collectors.toList());
3.3 flatMap - 扁平化映射
// 功能:将流中的每个元素映射为一个流,然后将所有流连接起来
<R> Stream<R> flatMap(Function<? super T, ? extends Stream<? extends R>> mapper)
使用场景:处理嵌套集合,将多层集合扁平化为一层
// 示例:获取所有用户的所有标签
List<String> allTags = userList.stream()
.flatMap(user -> user.getTags().stream())
.distinct()
.collect(Collectors.toList());
3.4 distinct - 去重
// 功能:去除重复元素
Stream<T> distinct()
使用场景:去除集合中的重复元素
// 示例:获取不重复的城市列表
List<String> uniqueCities = userList.stream()
.map(User::getCity)
.distinct()
.collect(Collectors.toList());
3.5 sorted - 排序
// 功能:对流中的元素进行排序
Stream<T> sorted()
Stream<T> sorted(Comparator<? super T> comparator)
使用场景:对数据进行排序处理
// 示例:按年龄对用户排序
List<User> sortedUsers = userList.stream()
.sorted(Comparator.comparing(User::getAge))
.collect(Collectors.toList());
3.6 peek - 元素遍历操作
// 功能:对流中的元素执行操作,主要用于调试
Stream<T> peek(Consumer<? super T> action)
使用场景:调试流操作或执行不改变元素的操作
// 示例:在处理过程中记录日志
List<User> processedUsers = userList.stream()
.peek(user -> log.info("Processing user: {}", user.getName()))
.filter(user -> user.getAge() > 20)
.collect(Collectors.toList());
3.7 limit - 限制元素数量
// 功能:限制流中元素的数量
Stream<T> limit(long maxSize)
使用场景:分页、限制结果集大小
// 示例:获取前5个用户
List<User> topFiveUsers = userList.stream()
.limit(5)
.collect(Collectors.toList());
3.8 skip - 跳过元素
// 功能:跳过前n个元素
Stream<T> skip(long n)
使用场景:分页查询
// 示例:分页查询(第2页,每页10条)
List<User> pageUsers = userList.stream()
.skip(10) // 跳过第1页
.limit(10) // 获取10条
.collect(Collectors.toList());
四、常用终端操作
4.1 collect - 收集结果
// 功能:将流中的元素收集到集合或其他容器中
<R, A> R collect(Collector<? super T, A, R> collector)
使用场景:将流转换为集合或其他数据结构
// 示例1:收集为List
List<User> userList = userStream.collect(Collectors.toList());
// 示例2:收集为Set
Set<String> uniqueNames = userStream
.map(User::getName)
.collect(Collectors.toSet());
// 示例3:收集为Map
Map<String, User> userMap = userStream
.collect(Collectors.toMap(User::getId, user -> user));
4.2 forEach - 遍历执行
// 功能:对流中的每个元素执行操作
void forEach(Consumer<? super T> action)
使用场景:遍历元素,执行操作
// 示例:发送邮件给所有用户
userList.stream()
.forEach(user -> emailService.sendEmail(user.getEmail(), "Hello", "Content"));
4.3 reduce - 归约
// 功能:将流中的元素组合起来,得到单个结果
Optional<T> reduce(BinaryOperator<T> accumulator)
T reduce(T identity, BinaryOperator<T> accumulator)
使用场景:求和、求最大值、连接字符串等
// 示例1:计算总和
int sum = numbers.stream()
.reduce(0, Integer::sum);
// 示例2:连接字符串
String combined = strings.stream()
.reduce("", (a, b) -> a + "," + b);
4.4 count - 计数
// 功能:计算流中的元素数量
long count()
使用场景:统计元素数量
// 示例:统计成年用户数量
long adultCount = userList.stream()
.filter(user -> user.getAge() >= 18)
.count();
4.5 anyMatch/allMatch/noneMatch - 匹配判断
// 功能:检查流中的元素是否满足条件
boolean anyMatch(Predicate<? super T> predicate) // 任意一个元素满足条件
boolean allMatch(Predicate<? super T> predicate) // 所有元素都满足条件
boolean noneMatch(Predicate<? super T> predicate) // 所有元素都不满足条件
使用场景:检查数据是否满足某些条件
// 示例1:检查是否有未成年用户
boolean hasMinors = userList.stream()
.anyMatch(user -> user.getAge() < 18);
// 示例2:检查是否所有用户都已验证
boolean allVerified = userList.stream()
.allMatch(User::isVerified);
4.6 findFirst/findAny - 查找元素
// 功能:返回流中的某个元素
Optional<T> findFirst() // 返回第一个元素
Optional<T> findAny() // 返回任意一个元素(在并行流中更高效)
使用场景:查找满足条件的元素
// 示例:查找第一个管理员用户
Optional<User> firstAdmin = userList.stream()
.filter(user -> "ADMIN".equals(user.getRole()))
.findFirst();
4.7 min/max - 最小值/最大值
// 功能:根据比较器返回流中的最小值/最大值
Optional<T> min(Comparator<? super T> comparator)
Optional<T> max(Comparator<? super T> comparator)
使用场景:查找最小/最大值元素
// 示例1:查找年龄最大的用户
Optional<User> oldestUser = userList.stream()
.max(Comparator.comparing(User::getAge));
// 示例2:查找最便宜的产品
Optional<Product> cheapestProduct = productList.stream()
.min(Comparator.comparing(Product::getPrice));
五、实际应用场景示例
5.1 数据转换与清洗
// 将实体列表转换为DTO列表并过滤掉无效数据
List<UserDTO> validUserDtos = userEntities.stream()
.filter(entity -> entity.getStatus().equals("ACTIVE"))
.map(entity -> {
UserDTO dto = new UserDTO();
dto.setId(entity.getId());
dto.setName(entity.getName());
dto.setEmail(entity.getEmail());
return dto;
})
.collect(Collectors.toList());
5.2 复杂业务统计
// 按部门统计员工平均工资
Map<String, Double> avgSalaryByDept = employees.stream()
.collect(Collectors.groupingBy(
Employee::getDepartment,
Collectors.averagingDouble(Employee::getSalary)
));
// 统计各年龄段用户数量
Map<String, Long> userCountByAgeGroup = users.stream()
.collect(Collectors.groupingBy(
user -> {
int age = user.getAge();
if (age < 18) return "未成年";
else if (age < 30) return "青年";
else if (age < 50) return "中年";
else return "老年";
},
Collectors.counting()
));
5.3 复杂数据过滤
// 查找满足多条件的订单
List<Order> filteredOrders = orders.stream()
.filter(order -> order.getAmount().compareTo(new BigDecimal("1000")) > 0)
.filter(order -> order.getStatus().equals("PAID"))
.filter(order -> order.getCreateTime().isAfter(LocalDateTime.now().minusDays(30)))
.collect(Collectors.toList());
5.4 集合操作
// 获取两个集合的交集
List<String> intersection = list1.stream()
.filter(list2::contains)
.collect(Collectors.toList());
// 获取两个集合的差集
List<String> difference = list1.stream()
.filter(item -> !list2.contains(item))
.collect(Collectors.toList());
5.5 数据分组与汇总
// 按状态分组订单并计算各组金额总和
Map<String, BigDecimal> orderTotalByStatus = orders.stream()
.collect(Collectors.groupingBy(
Order::getStatus,
Collectors.reducing(
BigDecimal.ZERO,
Order::getAmount,
BigDecimal::add
)
));
// 按多个属性分组
Map<String, Map<String, List<Product>>> productsByTypeAndBrand = products.stream()
.collect(Collectors.groupingBy(
Product::getType,
Collectors.groupingBy(Product::getBrand)
));
5.6 字符串处理
// 将句子中的单词提取、转小写、去重、排序
String sentence = "The quick brown fox jumps over the lazy dog";
List<String> uniqueWords = Arrays.stream(sentence.split("\\s+"))
.map(String::toLowerCase)
.distinct()
.sorted()
.collect(Collectors.toList());
5.7 并行处理大数据集
// 并行计算大数据集的统计信息
DoubleSummaryStatistics stats = largeNumberList.parallelStream()
.mapToDouble(Double::valueOf)
.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());
5.8 文件处理
// 读取文件并统计单词频率
Map<String, Long> wordFrequency = Files.lines(Paths.get("book.txt"))
.flatMap(line -> Arrays.stream(line.split("\\s+")))
.map(word -> word.replaceAll("[^a-zA-Z]", "").toLowerCase())
.filter(word -> !word.isEmpty())
.collect(Collectors.groupingBy(
Function.identity(),
Collectors.counting()
));
六、高级应用技巧
6.1 Collectors 高级用法
// 分区(将数据分为满足条件和不满足条件两组)
Map<Boolean, List<User>> partitionedUsers = users.stream()
.collect(Collectors.partitioningBy(user -> user.getAge() >= 18));
// 连接字符串
String joinedNames = users.stream()
.map(User::getName)
.collect(Collectors.joining(", ", "Names: [", "]"));
// 自定义收集器
Collector<Product, ?, BigDecimal> summingBigDecimal =
Collector.of(
() -> new BigDecimal[]{BigDecimal.ZERO},
(a, product) -> a[0] = a[0].add(product.getPrice()),
(a, b) -> {
a[0] = a[0].add(b[0]);
return a;
},
a -> a[0]
);
6.2 组合流操作
// 复杂过滤和转换的组合
List<TransactionDTO> result = transactions.stream()
.filter(tx -> tx.getAmount().compareTo(BigDecimal.valueOf(100)) > 0)
.filter(tx -> tx.getDate().isAfter(LocalDate.now().minusMonths(1)))
.sorted(Comparator.comparing(Transaction::getDate).reversed())
.limit(10)
.map(transactionMapper::toDTO)
.collect(Collectors.toList());
七、性能考虑
7.1 并行流性能优化
// 适合并行的场景:大数据量、元素独立计算、无状态操作
long count = veryLargeCollection.parallelStream()
.filter(complexFilter)
.count();
7.2 避免不必要的装箱/拆箱
// 使用基本类型流
double sum = IntStream.rangeClosed(1, 1000000)
.filter(n -> n % 2 == 0)
.average()
.orElse(0);