news 2026/4/18 7:16:03

Java Stream 实际用法详解

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
Java Stream 实际用法详解

一、Stream 基本概念

1.1 Stream 是什么

Java Stream 是 Java 8 引入的处理集合数据的 API,支持声明式编程和函数式操作。

// 传统方式 vs Stream 方式 List<String> names = Arrays.asList("Alice", "Bob", "Charlie"); // 传统方式 List<String> result = new ArrayList<>(); for (String name : names) { if (name.startsWith("A")) { result.add(name.toUpperCase()); } } // Stream 方式 List<String> result = names.stream() .filter(name -> name.startsWith("A")) .map(String::toUpperCase) .collect(Collectors.toList());

二、Stream 创建方式

2.1 从集合创建

// 从 List 创建 List<String> list = Arrays.asList("a", "b", "c"); Stream<String> stream1 = list.stream(); Stream<String> parallelStream = list.parallelStream(); // 从 Set 创建 Set<Integer> set = new HashSet<>(Arrays.asList(1, 2, 3)); Stream<Integer> stream2 = set.stream();

2.2 从数组创建

String[] array = {"a", "b", "c"}; Stream<String> stream = Arrays.stream(array); // 指定范围 Stream<String> rangeStream = Arrays.stream(array, 1, 3); // "b", "c"

2.3 使用 Stream.of()

Stream<String> stream = Stream.of("a", "b", "c"); Stream<Integer> intStream = Stream.of(1, 2, 3);

2.4 使用 Builder

Stream<String> stream = Stream.<String>builder() .add("a") .add("b") .add("c") .build();

2.5 生成无限流

// 生成无限序列 Stream<Integer> infiniteStream = Stream.iterate(0, n -> n + 2) .limit(10); // 限制为前10个 // 生成随机数 Stream<Double> randomStream = Stream.generate(Math::random) .limit(5);

2.6 基本类型 Stream

// IntStream IntStream intStream = IntStream.range(1, 10); // 1-9 IntStream closedIntStream = IntStream.rangeClosed(1, 10); // 1-10 // LongStream LongStream longStream = LongStream.range(1, 100); // DoubleStream DoubleStream doubleStream = DoubleStream.of(1.0, 2.0, 3.0);

三、中间操作(Intermediate Operations)

3.1 filter() - 过滤

List<String> names = Arrays.asList("Alice", "Bob", "Charlie", "David"); // 过滤长度大于3的名字 List<String> filtered = names.stream() .filter(name -> name.length() > 3) .collect(Collectors.toList()); // [Alice, Charlie, David] // 多条件过滤 List<String> multiFiltered = names.stream() .filter(name -> name.length() > 3) .filter(name -> name.startsWith("A")) .collect(Collectors.toList()); // [Alice]

3.2 map() - 映射转换

// 转换大小写 List<String> upperCaseNames = names.stream() .map(String::toUpperCase) .collect(Collectors.toList()); // 提取对象属性 class Person { private String name; private int age; // getters, setters } List<Person> persons = Arrays.asList( new Person("Alice", 25), new Person("Bob", 30) ); List<String> personNames = persons.stream() .map(Person::getName) .collect(Collectors.toList()); // 复杂转换 List<Integer> nameLengths = names.stream() .map(String::length) .collect(Collectors.toList());

3.3 flatMap() - 扁平化映射

// 将多个集合合并为一个流 List<List<String>> nestedList = Arrays.asList( Arrays.asList("a", "b"), Arrays.asList("c", "d") ); List<String> flatList = nestedList.stream() .flatMap(Collection::stream) .collect(Collectors.toList()); // [a, b, c, d] // 处理嵌套对象 class Order { private List<Item> items; // getter, setter } class Item { private String name; private double price; // getter, setter } List<Order> orders = Arrays.asList(order1, order2); List<Item> allItems = orders.stream() .flatMap(order -> order.getItems().stream()) .collect(Collectors.toList());

3.4 distinct() - 去重

List<Integer> numbers = Arrays.asList(1, 2, 2, 3, 3, 3, 4); List<Integer> distinctNumbers = numbers.stream() .distinct() .collect(Collectors.toList()); // [1, 2, 3, 4]

3.5 sorted() - 排序

// 自然排序 List<String> sortedNames = names.stream() .sorted() .collect(Collectors.toList()); // 自定义排序 List<Person> sortedByAge = persons.stream() .sorted(Comparator.comparingInt(Person::getAge)) .collect(Collectors.toList()); // 多重排序 List<Person> multiSorted = persons.stream() .sorted(Comparator.comparing(Person::getName) .thenComparing(Person::getAge)) .collect(Collectors.toList()); // 反向排序 List<Person> reverseSorted = persons.stream() .sorted(Comparator.comparing(Person::getAge).reversed()) .collect(Collectors.toList());

3.6 limit() 和 skip() - 限制和跳过

List<Integer> numbers = IntStream.rangeClosed(1, 10) .boxed() .collect(Collectors.toList()); // 获取前5个 List<Integer> firstFive = numbers.stream() .limit(5) .collect(Collectors.toList()); // [1, 2, 3, 4, 5] // 跳过前3个 List<Integer> skipThree = numbers.stream() .skip(3) .collect(Collectors.toList()); // [4, 5, 6, 7, 8, 9, 10] // 分页实现 int pageSize = 3; int pageNum = 2; // 第二页 List<Integer> page = numbers.stream() .skip((pageNum - 1) * pageSize) .limit(pageSize) .collect(Collectors.toList()); // [4, 5, 6]

3.7 peek() - 调试查看

List<String> result = names.stream() .peek(System.out::println) // 调试输出 .filter(name -> name.length() > 3) .peek(name -> System.out.println("Filtered: " + name)) .collect(Collectors.toList());

四、终端操作(Terminal Operations)

4.1 forEach() - 遍历

// 遍历输出 names.stream().forEach(System.out::println); // 并行流遍历(无序) names.parallelStream().forEach(System.out::println); // 并行流有序遍历 names.parallelStream().forEachOrdered(System.out::println);

4.2 collect() - 收集

// 收集到List List<String> list = names.stream() .filter(n -> n.length() > 3) .collect(Collectors.toList()); // 收集到Set(自动去重) Set<String> set = names.stream() .collect(Collectors.toSet()); // 收集到特定集合 TreeSet<String> treeSet = names.stream() .collect(Collectors.toCollection(TreeSet::new)); // 收集到Map Map<String, Integer> nameLengthMap = names.stream() .collect(Collectors.toMap( Function.identity(), // key: 名字本身 String::length // value: 名字长度 )); // 处理key冲突 Map<String, Integer> mapWithConflict = names.stream() .collect(Collectors.toMap( Function.identity(), String::length, (oldValue, newValue) -> oldValue // 冲突时保留旧值 ));

4.3 toArray() - 转换为数组

String[] array = names.stream().toArray(String[]::new); // 基本类型数组 int[] intArray = IntStream.range(1, 5).toArray();

4.4 reduce() - 归约

// 求和 Optional<Integer> sum = Stream.of(1, 2, 3, 4, 5) .reduce(Integer::sum); // 或 int sumResult = Stream.of(1, 2, 3, 4, 5) .reduce(0, Integer::sum); // 求最大值 Optional<Integer> max = Stream.of(1, 2, 3, 4, 5) .reduce(Integer::max); // 字符串连接 String concatenated = Stream.of("a", "b", "c") .reduce("", String::concat); // 复杂对象归约 class Order { private List<Item> items; // getter, setter } double totalPrice = orders.stream() .flatMap(order -> order.getItems().stream()) .map(Item::getPrice) .reduce(0.0, Double::sum);

4.5 匹配操作

List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5); // 任意匹配 boolean anyMatch = numbers.stream() .anyMatch(n -> n > 3); // true // 全部匹配 boolean allMatch = numbers.stream() .allMatch(n -> n > 0); // true // 无匹配 boolean noneMatch = numbers.stream() .noneMatch(n -> n < 0); // true

4.6 查找操作

Optional<String> first = names.stream() .filter(n -> n.startsWith("A")) .findFirst(); // 返回第一个元素 Optional<String> any = names.stream() .filter(n -> n.startsWith("A")) .findAny(); // 并行流中效率更高

4.7 统计操作

// 计数 long count = names.stream().count(); // 使用 IntStream 统计 IntSummaryStatistics stats = IntStream.range(1, 100) .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());

五、Collectors 高级用法

5.1 分组

List<Person> persons = Arrays.asList( new Person("Alice", 25, "New York"), new Person("Bob", 30, "New York"), new Person("Charlie", 25, "London") ); // 按年龄分组 Map<Integer, List<Person>> groupByAge = persons.stream() .collect(Collectors.groupingBy(Person::getAge)); // 多级分组 Map<Integer, Map<String, List<Person>>> multiGroup = persons.stream() .collect(Collectors.groupingBy( Person::getAge, Collectors.groupingBy(Person::getCity) )); // 分组并计数 Map<Integer, Long> ageCount = persons.stream() .collect(Collectors.groupingBy( Person::getAge, Collectors.counting() )); // 分组并求平均值 Map<Integer, Double> averageAgeByCity = persons.stream() .collect(Collectors.groupingBy( Person::getAge, Collectors.averagingInt(Person::getAge) ));

5.2 分区

// 按条件分区 Map<Boolean, List<Person>> partition = persons.stream() .collect(Collectors.partitioningBy(p -> p.getAge() > 25)); // 分区并统计 Map<Boolean, Long> partitionCount = persons.stream() .collect(Collectors.partitioningBy( p -> p.getAge() > 25, Collectors.counting() ));

5.3 连接字符串

// 简单连接 String joined = names.stream() .collect(Collectors.joining()); // "AliceBobCharlie" // 带分隔符 String joinedWithComma = names.stream() .collect(Collectors.joining(", ")); // "Alice, Bob, Charlie" // 带前缀和后缀 String joinedFull = names.stream() .collect(Collectors.joining(", ", "[", "]")); // "[Alice, Bob, Charlie]"

5.4 统计汇总

// 求总和 int totalAge = persons.stream() .collect(Collectors.summingInt(Person::getAge)); // 求平均值 double averageAge = persons.stream() .collect(Collectors.averagingInt(Person::getAge)); // 综合统计 IntSummaryStatistics ageStats = persons.stream() .collect(Collectors.summarizingInt(Person::getAge));

六、并行流(Parallel Stream)

6.1 创建并行流

// 从集合创建并行流 List<String> names = Arrays.asList("Alice", "Bob", "Charlie"); Stream<String> parallelStream = names.parallelStream(); // 将顺序流转为并行流 Stream<String> parallel = names.stream().parallel(); // 将并行流转为顺序流 Stream<String> sequential = parallelStream.sequential();

6.2 并行流注意事项

// 非线程安全操作(错误示例) List<Integer> unsafeList = new ArrayList<>(); IntStream.range(0, 10000).parallel() .forEach(unsafeList::add); // 可能丢失数据 // 线程安全操作(正确示例) List<Integer> safeList = IntStream.range(0, 10000).parallel() .boxed() .collect(Collectors.toList()); // 并行流排序 List<Integer> sortedParallel = IntStream.range(0, 10000).parallel() .sorted() .boxed() .collect(Collectors.toList());

6.3 并行流性能考虑

// 小数据量顺序流更快 List<Integer> smallList = IntStream.range(0, 100) .boxed().collect(Collectors.toList()); long start = System.currentTimeMillis(); smallList.stream().map(i -> i * 2).count(); long sequentialTime = System.currentTimeMillis() - start; start = System.currentTimeMillis(); smallList.parallelStream().map(i -> i * 2).count(); long parallelTime = System.currentTimeMillis() - start; System.out.println("Sequential: " + sequentialTime + "ms"); System.out.println("Parallel: " + parallelTime + "ms");

七、实战案例

7.1 数据处理管道

public class StreamPipelineExample { public static void main(String[] args) { List<Transaction> transactions = Arrays.asList( new Transaction("USD", 1000.0, Transaction.Type.DEPOSIT), new Transaction("USD", 500.0, Transaction.Type.WITHDRAWAL), new Transaction("EUR", 800.0, Transaction.Type.DEPOSIT), new Transaction("USD", 300.0, Transaction.Type.DEPOSIT), new Transaction("JPY", 10000.0, Transaction.Type.WITHDRAWAL) ); // 复杂数据处理管道 Map<String, Double> totalDepositsByCurrency = transactions.stream() .filter(t -> t.getType() == Transaction.Type.DEPOSIT) .filter(t -> t.getAmount() > 200) .collect(Collectors.groupingBy( Transaction::getCurrency, Collectors.summingDouble(Transaction::getAmount) )); totalDepositsByCurrency.forEach((currency, total) -> System.out.println(currency + ": " + total)); } }

7.2 文件处理

public class FileStreamExample { public static void main(String[] args) throws IOException { // 读取文件并处理 List<String> lines = Files.lines(Paths.get("data.txt")) .filter(line -> !line.trim().isEmpty()) .map(String::toUpperCase) .sorted() .collect(Collectors.toList()); // 写入文件 Files.write(Paths.get("output.txt"), lines); } }

7.3 数据库查询模拟

public class DatabaseStreamExample { public static List<User> findActiveUsers(List<User> users) { return users.stream() .filter(User::isActive) .filter(user -> user.getLastLogin().isAfter(LocalDate.now().minusDays(30))) .sorted(Comparator.comparing(User::getLastLogin).reversed()) .collect(Collectors.toList()); } }

八、性能优化建议

8.1 使用基本类型流

// 避免装箱拆箱开销 // 不好 List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5); int sum = numbers.stream() .mapToInt(Integer::intValue) // 需要拆箱 .sum(); // 好 int sum = IntStream.rangeClosed(1, 5).sum();

8.2 短路操作优化

// 使用短路操作提前结束 boolean hasMatch = largeList.stream() .filter(this::expensiveOperation) .anyMatch(this::condition); // 找到第一个匹配就停止

8.3 避免重复计算

// 不好 - 重复计算 List<String> result = names.stream() .filter(name -> expensiveCheck(name)) .map(name -> transform(name)) .filter(transformed -> expensiveCheck(transformed)) .collect(Collectors.toList()); // 好 - 缓存中间结果 List<String> filtered = names.stream() .filter(name -> expensiveCheck(name)) .collect(Collectors.toList()); List<String> result = filtered.stream() .map(name -> transform(name)) .filter(transformed -> expensiveCheck(transformed)) .collect(Collectors.toList());

九、常见陷阱

9.1 Stream 只能消费一次

Stream<String> stream = names.stream(); stream.forEach(System.out::println); // stream.count(); // 错误!Stream 已经关闭

9.2 空指针处理

// 使用 Optional 避免空指针 Optional<String> first = names.stream() .filter(Objects::nonNull) .findFirst(); // 或者在创建 Stream 时处理 Stream<String> safeStream = Optional.ofNullable(names) .orElse(Collections.emptyList()) .stream();

9.3 修改外部状态

// 避免副作用 List<String> result = new ArrayList<>(); names.stream() .forEach(result::add); // 不好 // 使用 collect List<String> goodResult = names.stream() .collect(Collectors.toList()); // 好

总结

Java Stream 提供了强大、灵活的数据处理能力,核心要点:

  1. 创建流:多种创建方式,灵活选择

  2. 中间操作:链式调用,延迟执行

  3. 终端操作:触发计算,产生结果

  4. 并行流:合理使用提升性能

  5. Collectors:强大的结果收集工具

在实际开发中,应根据具体场景选择合适的流操作,注意性能优化,避免常见陷阱。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/4/18 2:45:57

【完整源码+数据集+部署教程】天线检测与目标识别系统源码分享[一条龙教学YOLOV8标注好的数据集一键训练_70+全套改进创新点发刊_Web前端展示]

一、背景意义 随着无线通信技术的迅猛发展&#xff0c;天线作为无线信号传输和接收的关键组件&#xff0c;其检测与识别的重要性日益凸显。传统的天线检测方法多依赖于人工巡检和经验判断&#xff0c;效率低下且容易受到人为因素的影响&#xff0c;难以满足现代通信网络对高效、…

作者头像 李华
网站建设 2026/4/18 2:45:49

拉普拉斯特征图-目标函数化简推导(手写详细)

学到了很多算法和公式&#xff0c;老师们总是一带而过&#xff0c;这里按照老师课件中推导了一次&#xff0c;并补充了比较困惑的内容&#xff1a;tr&#xff08;迹&#xff09;是怎么被引入公式的这里发现还有两个地方需要补充一下&#xff1a;1.矩阵求导法则/迹求导法则2.广义…

作者头像 李华
网站建设 2026/4/17 8:24:37

Windows GUI 逆向分析题(CrackMe)

首先下载文件在detect it easy中进行查壳&#xff0c;从 DIE 结果可以知道&#xff1a;PE32&#xff0c;32 位 GUI 程序&#xff08;Windows GUI&#xff09;编译器&#xff1a;Microsoft Visual C/C (12.00.9782)调试信息&#xff1a;包含 PDB 路径&#xff08;说明可能有符号…

作者头像 李华
网站建设 2026/4/18 2:41:46

GBA卡带贴纸999张

GBA卡带图片&#xff0c;拿来做游戏封面很好看&#xff0c;一直想找这套资源&#xff0c;找了很久才找到&#xff0c;然后分享一下吧全能模拟器可以联网下载封面&#xff0c;但是不是卡带贴纸&#xff0c;这个是另外的。https://pan.quark.cn/s/94acec7b9b63

作者头像 李华