Java Stream 流使用详解
·
一、Stream 特点:
-
不存储数据,只是数据源的一个视图
-
函数式编程,对流的操作产生一个新流
-
延迟执行,中间操作都是惰性的
-
不可重复使用,消费后会失效
二、 创建方式
// 1. 从集合创建
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("a", "b", "c");
// 3. 使用 Stream.builder()
Stream<String> stream4 = Stream.<String>builder()
.add("a")
.add("b")
.add("c")
.build();
// 4. 生成无限流
Stream<Integer> generate = Stream.generate(() -> 1).limit(10);
Stream<Integer> iterate = Stream.iterate(0, n -> n + 2).limit(10);
// 5. 基本类型特化流
IntStream intStream = IntStream.range(1, 10); // 1-9
IntStream intStream2 = IntStream.rangeClosed(1, 10); // 1-10
三、使用
1. 筛选与切片
// filter - 筛选条件 过滤元素
List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5, 6);
List<Integer> even = numbers.stream()
.filter(n -> n % 2 == 0)
.collect(Collectors.toList()); // [2, 4, 6]
// distinct - 去重
List<Integer> withDuplicates = Arrays.asList(1, 2, 2, 3, 3, 4);
List<Integer> distinct = withDuplicates.stream()
.distinct()
.collect(Collectors.toList()); // [1, 2, 3, 4]
// limit - 限制数量
List<Integer> firstThree = numbers.stream()
.limit(3)
.collect(Collectors.toList()); // [1, 2, 3]
// skip - 跳过前几个元素
List<Integer> afterSkip = numbers.stream()
.skip(2)
.collect(Collectors.toList()); // [3, 4, 5, 6]
2. 映射
// map - 元素转换
List<String> words = Arrays.asList("111", "222");
List<Integer> lengths = words.stream()
.map(Integer::parseInt)
.collect(Collectors.toList()); // [111, 222]
// 对象属性提取
List<User> users = getUsers();
List<String> names = users.stream()
.map(User::getName)
.collect(Collectors.toList());
// flatMap - 扁平化映射
List<List<Integer>> listOfLists = Arrays.asList(
Arrays.asList(1, 2),
Arrays.asList(3, 4),
Arrays.asList(5, 6)
);
List<Integer> flatList = listOfLists.stream()
.flatMap(Collection::stream)
.collect(Collectors.toList()); // [1, 2, 3, 4, 5, 6]
// 拆分字符串
List<String> sentences = Arrays.asList("Hello World", "Java Stream");
List<String> words2 = sentences.stream()
.flatMap(s -> Arrays.stream(s.split(" ")))
.collect(Collectors.toList()); // ["Hello", "World", "Java", "Stream"]
3. 排序
// sorted - 自然排序
List<Integer> unsorted = Arrays.asList(3, 1, 4, 1, 5);
List<Integer> sorted = unsorted.stream()
.sorted()
.collect(Collectors.toList()); // [1, 1, 3, 4, 5]
// 自定义排序
List<User> sortedUsers = users.stream()
.sorted(Comparator.comparing(User::getAge))
.collect(Collectors.toList());
// 多级排序
List<User> sortedUsers2 = users.stream()
.sorted(Comparator.comparing(User::getAge)
.thenComparing(User::getName))
.collect(Collectors.toList());
// 反向排序
List<Integer> reverseSorted = unsorted.stream()
.sorted(Comparator.reverseOrder())
.collect(Collectors.toList()); // [5, 4, 3, 1, 1]
4. 调试
// peek - 查看中间结果
List<Integer> result = Stream.of(1, 2, 3, 4)
.peek(x -> System.out.println("原始值: " + x))
.map(x -> x * 2)
.peek(x -> System.out.println("映射后: " + x))
.filter(x -> x > 5)
.peek(x -> System.out.println("过滤后: " + x))
.collect(Collectors.toList());
5. 匹配与查找
// allMatch - 全部匹配
boolean allEven = numbers.stream().allMatch(n -> n % 2 == 0);
// anyMatch - 任一匹配
boolean hasEven = numbers.stream().anyMatch(n -> n % 2 == 0);
// noneMatch - 无匹配
boolean noNegative = numbers.stream().noneMatch(n -> n < 0);
// findFirst - 返回第一个
Optional<Integer> first = numbers.stream()
.filter(n -> n > 3)
.findFirst();
// findAny - 返回任意一个(并行流中效率高)
Optional<Integer> any = numbers.parallelStream()
.filter(n -> n > 3)
.findAny();
6. 归约
// count - 计数
long count = numbers.stream().count();
long evenCount = numbers.stream().filter(n -> n % 2 == 0).count();
// max/min - 最大/最小值
Optional<Integer> max = numbers.stream().max(Integer::compareTo);
Optional<Integer> min = numbers.stream().min(Integer::compareTo);
// reduce - 累积计算
// 求和
Optional<Integer> sum = numbers.stream().reduce((a, b) -> a + b);
// 带初始值
Integer sumWithInit = numbers.stream().reduce(0, (a, b) -> a + b);
// 方法引用
Integer sumWithMethod = numbers.stream().reduce(0, Integer::sum);
// 求最大值
Optional<Integer> max2 = numbers.stream().reduce(Integer::max);
// 字符串拼接
List<String> strs = Arrays.asList("a", "b", "c");
String concat = strs.stream().reduce("", (a, b) -> a + b); // "abc"
7. 收集
// collect - 收集到集合
// 转 List
List<String> nameList = users.stream()
.map(User::getName)
.collect(Collectors.toList());
// 转 Set(自动去重)
Set<String> nameSet = users.stream()
.map(User::getName)
.collect(Collectors.toSet());
// 转特定集合类型
ArrayList<String> arrayList = users.stream()
.map(User::getName)
.collect(Collectors.toCollection(ArrayList::new));
TreeSet<String> treeSet = users.stream()
.map(User::getName)
.collect(Collectors.toCollection(TreeSet::new));
// 转 Map
Map<Integer, String> userMap = users.stream()
.collect(Collectors.toMap(
User::getId, // key mapper
User::getName, // value mapper
(v1, v2) -> v1 // 冲突解决
));
// 分组
Map<Integer, List<User>> groupByAge = users.stream()
.collect(Collectors.groupingBy(User::getAge));
// 多级分组
Map<Integer, Map<String, List<User>>> multiGroup = users.stream()
.collect(Collectors.groupingBy(User::getAge,
Collectors.groupingBy(User::getGender)));
// 分区(true/false两组)
Map<Boolean, List<Integer>> partition = numbers.stream()
.collect(Collectors.partitioningBy(n -> n > 3));
// 连接字符串
String joined = words.stream()
.collect(Collectors.joining(", ", "[", "]"));
// 输出: [hello, world]
// 汇总统计
IntSummaryStatistics stats = numbers.stream()
.collect(Collectors.summarizingInt(Integer::intValue));
System.out.println(stats.getSum());
System.out.println(stats.getAverage());
System.out.println(stats.getMax());
System.out.println(stats.getMin());
System.out.println(stats.getCount());
四、数值流特化
// IntStream, LongStream, DoubleStream 避免装箱开销
int[] intArray = {1, 2, 3, 4, 5};
// 范围操作
IntStream.range(1, 10).forEach(System.out::print); // 123456789
IntStream.rangeClosed(1, 10).forEach(System.out::print); // 12345678910
// 数值计算
int sum = IntStream.of(1, 2, 3, 4, 5).sum();
OptionalDouble avg = IntStream.of(1, 2, 3, 4, 5).average();
int max = IntStream.of(1, 2, 3, 4, 5).max().getAsInt();
// 对象流转数值流
List<User> users = getUsers();
int totalAge = users.stream()
.mapToInt(User::getAge)
.sum();
double avgAge = users.stream()
.mapToInt(User::getAge)
.average()
.orElse(0);
// 数值流转回对象流
Stream<String> boxedStream = IntStream.range(1, 5)
.boxed()
.map(Object::toString);
五、并行流
// 创建并行流
List<Integer> list = Arrays.asList(1, 2, 3, 4, 5, 6, 7, 8, 9, 10);
list.parallelStream().forEach(System.out::println);
// 将串行流转并行
list.stream().parallel().forEach(System.out::println);
// 并行流归约(线程安全)
int sum = list.parallelStream()
.reduce(0, Integer::sum); // 正确
// 错误用法 - 非线程安全的集合
List<Integer> wrongResult = new ArrayList<>();
list.parallelStream()
.forEach(wrongResult::add); // 可能丢失数据或抛异常
// 正确用法
List<Integer> rightResult = list.parallelStream()
.collect(Collectors.toList());
// 控制并行度
System.setProperty("java.util.concurrent.ForkJoinPool.common.parallelism", "4");
六、案例
案例1:复杂对象处理
@Data
@AllArgsConstructor
class Order {
private Long id;
private Double amount;
private LocalDateTime createTime;
private List<OrderItem> items;
}
@Data
@AllArgsConstructor
class OrderItem {
private String productName;
private Integer quantity;
private Double price;
}
// 统计每个用户的总订单金额
Map<User, Double> userTotalAmount = orders.stream()
.collect(Collectors.groupingBy(
Order::getUser,
Collectors.summingDouble(Order::getAmount)
));
// 获取最近7天的订单数量
long recentOrders = orders.stream()
.filter(order -> order.getCreateTime()
.isAfter(LocalDateTime.now().minusDays(7)))
.count();
// 计算订单总金额
double totalAmount = orders.stream()
.mapToDouble(Order::getAmount)
.sum();
// 获取最贵的订单
Optional<Order> maxOrder = orders.stream()
.max(Comparator.comparing(Order::getAmount));
// 订单金额分布(区间)
Map<String, List<Order>> amountDistribution = orders.stream()
.collect(Collectors.groupingBy(order -> {
if (order.getAmount() < 100) return "小额";
if (order.getAmount() < 1000) return "中额";
return "大额";
}));
案例2:文件处理
// 读取文件并统计单词频率
try (Stream<String> lines = Files.lines(Paths.get("file.txt"))) {
Map<String, Long> wordCount = lines
.flatMap(line -> Arrays.stream(line.split("\\W+")))
.filter(word -> word.length() > 0)
.map(String::toLowerCase)
.collect(Collectors.groupingBy(
Function.identity(),
Collectors.counting()
));
// 获取前10个高频词
wordCount.entrySet().stream()
.sorted(Map.Entry.<String, Long>comparingByValue().reversed())
.limit(10)
.forEach(e -> System.out.println(e.getKey() + ": " + e.getValue()));
}
七、踩坑记录
1. Stream 不可重用
Stream<String> stream = list.stream();
stream.forEach(System.out::println);
stream.forEach(System.out::println); // 抛异常: stream has already been operated upon
2. 无限流必须限制
Stream.generate(Math::random)
.limit(10) // 必须添加限制
.forEach(System.out::println);
3. Lambda 外部变量必须是 final 或 effectively final
String prefix = "User: ";
Stream.of("Alice", "Bob")
.map(name -> prefix + name) // prefix 是 effectively final
.forEach(System.out::println);
4. 短路操作优化
// findFirst, findAny, limit, anyMatch 都是短路操作
// 应该尽早使用
list.stream()
.filter(this::expensiveOperation) // 昂贵的操作
.findFirst() // 只执行到第一个匹配
.ifPresent(System.out::println);
持续更新中。。。。。。
更多推荐

所有评论(0)