本文详细介绍了 Java Stream 流的重要知识点。包括数据源与操作分离(不存储数据,不可复用)、惰性求值与短路优化;以及流的创建方式,如集合创建、数组 / 值创建、文件创建;然后介绍中间操作,像过滤与切片等;还涉及终止操作、集合归约与 Collectors 工具类、并行流与线程安全、性能优化与日常工作中使用Java Stream的注意点等等。
Stream不存储数据,仅对数据源(如集合、数组、I/O)进行计算。需要注意的是,流是不可复用的,一旦流被消费,就不能再次使用,否则会抛出IllegalStateException
异常。
filter
、map
)是延迟执行的,只有当遇到终止操作(如collect
)时才会触发计算。findFirst
、anyMatch
)可以提前终止遍历,减少不必要的计算。List<String> list = Arrays.asList("a", "b");
Stream<String> stream = list.stream(); // 顺序流
Stream<String> parallelStream = list.parallelStream(); // 并行流
Stream<String> stream1 = Stream.of("a", "b");
Stream<String> stream2 = Arrays.stream(new String[]{"a", "b"});
Stream<String> lines = Files.lines(Paths.get("data.txt")); // 读取文件
filter(Predicate)
:用于过滤元素。distinct()
:去除重复元素。limit(n)
:截断前n个元素。skip(n)
:跳过前n个元素。map(Function)
:一对一转换,提取对象的某个字段。flatMap(Function)
:扁平化操作,可将List>
转为List
。sorted()
:自然排序。sorted(Comparator)
:自定义排序。.peek(e -> System.out.println("Processing: " + e))
anyMatch(Predicate)
:判断是否有任一元素满足条件。allMatch(Predicate)
:判断是否所有元素都满足条件。findFirst()
:返回第一个元素(返回类型为Optional
)。findAny()
:返回任意元素,在并行流中更高效。reduce(BinaryOperator)
:用于聚合操作,如求和。collect(Collectors)
:将流转换为集合(如List、Map)。count()
:统计元素总数。max(Comparator)
/min(Comparator)
:找出元素的极值。forEach(Consumer)
:遍历元素,无顺序保证。forEachOrdered(Consumer)
:按顺序遍历元素。List<String> list = stream.collect(Collectors.toList());
Set<String> set = stream.collect(Collectors.toSet());
Map<String, User> map = stream.collect(Collectors.toMap(User::getId, Function.identity()));
// 按年龄分组
Map<Integer, List<User>> ageGroup = users.stream()
.collect(Collectors.groupingBy(User::getAge));
// 跟据年龄是否>=18进行分区
Map<Boolean, List<User>> partition = users.stream()
.collect(Collectors.partitioningBy(u -> u.getAge() >= 18));
Double average = users.stream()
.collect(Collectors.averagingInt(User::getAge)); // 平均年龄
String names = users.stream()
.map(User::getName)
.collect(Collectors.joining(", ")); // 拼接字符串
List<Integer> result = list.parallelStream()
.filter(n -> n % 2 == 0)
.collect(Collectors.toList());
错误示例:
for (int i = 0; i < 10; i++) {
list.stream().filter(...); // 多次创建流
}
IntStream
、LongStream
、DoubleStream
可以避免装箱开销:
IntStream.range(0, 100).sum(); // 比Stream高效
尽早使用limit
、findFirst
等操作可以减少计算量:
users.stream()
.filter(u -> u.getAge() > 30)
.findFirst() // 找到第一个符合条件后即终止
.orElse(null);
// 计算所有订单总金额
double totalAmount = orders.stream()
.mapToDouble(Order::getAmount)
.sum();
// 按用户分组统计消费总额
Map<Long, Double> userTotal = orders.stream()
.collect(Collectors.groupingBy(
Order::getUserId,
Collectors.summingDouble(Order::getAmount)
));
// 筛选库存>0的商品并按价格排序
List<Product> availableProducts = products.stream()
.filter(p -> p.getStock() > 0)
.sorted(Comparator.comparing(Product::getPrice))
.collect(Collectors.toList());
// 统计最近一周活跃用户数
long activeUsers = userLogs.stream()
.filter(log -> log.getAction().equals("LOGIN"))
.filter(log -> log.getTime().isAfter(LocalDateTime.now().minusDays(7)))
.map(UserLog::getUserId)
.distinct()
.count();
在日常开发中,合理运用Stream流可以让代码更加简洁、高效,提高开发效率。希望本文对你有所帮助!
← 上一篇 Java进阶——数据类型深入解析 |
记得点赞、关注、收藏哦!
|
下一篇 Java进阶——注解一文全懂 → |