JDK 8 Stream API 教程文档
来源:     阅读:3
易浩激活码
发布于 2025-11-15 19:17
查看主页

Stream 简介

Stream 是 JDK 8 中处理集合(Collection)数据的新抽象,它可以让你以声明式的方式处理数据,类似于使用 SQL 语句进行数据库查询。

List names = Arrays.asList("Alice", "Bob", "Charlie", "David");

// 传统方式
List<String> result = new ArrayList<>();
for (String name : names) {
    if (name.startsWith("A")) {
        result.add(name.toUpperCase());
    }
}

// Stream 方式 List<String> streamResult = names.stream() .filter(name -> name.startsWith("A")) .map(String::toUpperCase) .collect(Collectors.toList());
 #后端 #每天一个知识点

Stream 的特点

  1. 不是数据结构 :Stream 不会存储数据,只是对数据源进行计算
  2. 不修改源数据 :对 Stream 的操作不会影响原始数据源
  3. 惰性执行 :中间操作是惰性的,只有在终止操作时才会执行
  4. 可消费性 :Stream 只能被消费一次

Stream 操作分类

| 操作类型 | 方法示例 | 返回值 | 特点 | | ---

| 中间操作 | filter(), map(), sorted() | Stream | 惰性执行,可链式调用 | | 终止操作 | forEach(), collect(), count() | 非 Stream | 立即执行,关闭流 |

创建 Stream

1. 从集合创建

List<String> list = Arrays.asList("a", "b", "c");
Stream<String> stream = list.stream();

2. 从数组创建

String[] array = {"a", "b", "c"};
Stream<String> stream = Arrays.stream(array);

3. 使用 Stream.of()

Stream<String> stream = Stream.of("a", "b", "c");

4. 创建数值流

IntStream intStream = IntStream.range(1, 5);     // 1,2,3,4
IntStream closedStream = IntStream.rangeClosed(1, 5); // 1,2,3,4,5

5. 创建无限流

// 生成10个随机数
Stream<Double> randomStream = Stream.generate(Math::random).limit(10);

// 创建斐波那契数列 Stream.iterate(new int[]{0, 1}, t -> new int[]{t[1], t[0] + t[1]}) .limit(10) .map(t -> t[0]) .forEach(System.out::println);

中间操作

1. filter() - 过滤

List<String> names = Arrays.asList("Alice", "Bob", "Charlie", "David");
List<String> result = names.stream()
    .filter(name -> name.length() > 3)
    .collect(Collectors.toList());
// 结果: [Alice, Charlie, David]

2. map() - 映射

List<String> names = Arrays.asList("Alice", "Bob", "Charlie");
List<Integer> nameLengths = names.stream()
    .map(String::length)
    .collect(Collectors.toList());
// 结果: [5, 3, 7]

3. flatMap() - 扁平化映射

List<List<String>> listOfLists = Arrays.asList(
    Arrays.asList("a", "b"),
    Arrays.asList("c", "d")
);

List<String> flatList = listOfLists.stream() .flatMap(List::stream) .collect(Collectors.toList()); // 结果: [a, b, c, d]

C 4. distinct() - 去重

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

5. sorted() - 排序

List<String> names = Arrays.asList("Charlie", "Alice", "Bob");
List<String> sortedNames = names.stream()
    .sorted()
    .collect(Collectors.toList());
// 结果: [Alice, Bob, Charlie]

// 自定义排序 List<String> customSorted = names.stream() .sorted((a, b) -> b.length() - a.length()) .collect(Collectors.toList()); // 结果: [Charlie, Alice, Bob]

6. limit() 和 skip() - 限制和跳过

List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5, 6, 7, 8, 9, 10);

List<Integer> limited = numbers.stream() .limit(5) .collect(Collectors.toList()); // 结果: [1, 2, 3, 4, 5]

List<Integer> skipped = numbers.stream() .skip(5) .collect(Collectors.toList()); // 结果: [6, 7, 8, 9, 10]

7. peek() - 查看元素(主要用于调试)

List<String> result = Stream.of("one", "two", "three")
    .filter(s -> s.length() > 3)
    .peek(s -> System.out.println("Filtered value: " + s))
    .map(String::toUpperCase)
    .peek(s -> System.out.println("Mapped value: " + s))
    .collect(Collectors.toList());

终止操作

C 1. forEach() - 遍历

List<String> names = Arrays.asList("Alice", "Bob", "Charlie");
names.stream().forEach(System.out::println);

C 2. collect() - 收集

// 转换为List
List<String> list = stream.collect(Collectors.toList());

// 转换为 Set Set<String> set = stream.collect(Collectors.toSet());

// 转换为 Map Map<String, Integer> map = stream.collect( Collectors.toMap(s -> s, String::length) );

// 连接字符串 String joined = stream.collect(Collectors.joining(", "));

// 分组 Map<Integer, List<String>> grouped = names.stream() .collect(Collectors.groupingBy(String::length));

// 分区 Map<Boolean, List<String>> partitioned = names.stream() .collect(Collectors.partitioningBy(s -> s.length() > 3));

C 3. reduce() - 归约

List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5);

// 求和 Optional<Integer> sum = numbers.stream().reduce(Integer::sum); // 或 Integer sum2 = numbers.stream().reduce(0, Integer::sum);

// 求最大值 Optional<Integer> max = numbers.stream().reduce(Integer::max);

// 字符串连接 Optional<String> concat = Stream.of("a", "b", "c").reduce(String::concat);

4. 匹配操作

List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5);

boolean allEven = numbers.stream().allMatch(n -> n % 2 == 0); // false boolean anyEven = numbers.stream().anyMatch(n -> n % 2 == 0); // true boolean noneEven = numbers.stream().noneMatch(n -> n % 2 == 0); // false

5. 查找操作

List<String> names = Arrays.asList("Alice", "Bob", "Charlie");

Optional<String> first = names.stream().findFirst(); Optional<String> any = names.stream().findAny();

6. 统计操作

List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5);

long count = numbers.stream().count(); IntSummaryStatistics stats = numbers.stream() .mapToInt(Integer::intValue) .summaryStatistics();

System.out.println("最大值: " +

System.out.println("最小值: " +

System.out.println("总和: " +

System.out.println("平均值: " + stats.getAverage());

并行流

创建并行流

List<String> names = Arrays.asList("Alice", "Bob", "Charlie");

// 方法1:从集合创建 Stream<String> parallelStream = names.parallelStream();

// 方法2:将顺序流转为并行流 Stream<String> parallel = names.stream().parallel();

并行流示例

List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5, 6, 7, 8, 9, 10);

long startTime = System.currentTimeMillis(); long sum = numbers.parallelStream() .mapToLong(Integer::longValue) .sum(); long endTime = System.currentTimeMillis();

System.out.println("总和: " +

System.out.println("执行时间: " + (endTime - startTime) + "ms");

并行流注意事项

  1. 线程安全 :确保操作是线程安全的
  2. 状态无关 :避免有状态的lambda表达式
  3. 顺序敏感 :某些操作(如findFirst)在并行流中性能可能更差
  4. 数据量 :小数据量使用并行流可能适得其反

实战示例

示例1:员工数据处理

class Employee {
    private String name;
    private String department;
    private double salary;
    private int age;

    // 构造方法、getter、setter省略
}

List<Employee> employees = Arrays.asList( new Employee("Alice", "IT", 5000, 25), new Employee("Bob", "HR", 4000, 30), new Employee("Charlie", "IT", 6000, 35), new Employee("David", "Finance", 5500, 28) );

// 1.

Map<String, Double> avgSalaryByDept = employees.stream() .collect(Collectors.groupingBy( Employee::getDepartment, Collectors.averagingDouble(Employee::getSalary) ));

// 2.

Optional<Employee> highestPaidInIT = employees.stream() .filter(e -> "IT".equals(e.getDepartment())) .max(Comparator.comparingDouble(Employee::getSalary));

// 3.

List<Employee> top3ByAge = employees.stream() .sorted(Comparator.comparingInt(Employee::getAge).reversed()) .limit(3) .collect(Collectors.toList());

// 4.

Map<String, Long> employeeCountByDept = employees.stream() .collect(Collectors.groupingBy( Employee::getDepartment, Collectors.counting() ));

示例2:文件处理

// 读取文件并统计单词频率
try (Stream<String> lines = Files.lines(Paths.get("file.txt"))) {
    Map<String, Long> wordCount = lines
        .flatMap(line -> Arrays.stream(line.split("s+")))
        .map(word -> word.replaceAll("[^a-zA-Z]", "").toLowerCase())
        .filter(word -> !word.isEmpty())
        .collect(Collectors.groupingBy(
            word -> word,
            Collectors.counting()
        ));

    // 按频率排序
    wordCount.entrySet().stream()
        .sorted(Map.Entry.<String, Long>comparingByValue().reversed())
        .limit(10)
        .forEach(entry ->

System.out.println(entry.getKey() + ": " + entry.getValue()) ); } catch (IOException e) { e.printStackTrace(); }

示例3:复杂数据转换

// 多层数据转换和聚合
class Order {
    private String customer;
    private List<OrderItem> items;
    private LocalDate orderDate;
    // 构造方法、getter、setter省略
}

class OrderItem { private String product; private int quantity; private double price; // 构造方法、getter、setter 省略 }

List<Order> orders = // 初始化订单数据

// 计算每个客户的总消费金额 Map<String, Double> customerTotal = orders.stream() .collect(Collectors.groupingBy( Order::getCustomer, Collectors.summingDouble(order ->

order.getItems().stream() .mapToDouble(item -> item.getQuantity() * item.getPrice()) .sum() ) ));

// 找出最畅销的产品 Optional<String> bestSellingProduct = orders.stream() .flatMap(order -> order.getItems().stream()) .collect(Collectors.groupingBy( OrderItem::getProduct, Collectors.summingInt(OrderItem::getQuantity) )) .entrySet().stream() .max(Map.Entry.comparingByValue()) .map(Map.Entry::getKey);

最佳实践

  1. 优先使用方法引用 :使代码更简洁
  2. 避免副作用 :保持函数的纯粹性
  3. 合理使用并行流 :根据数据量和操作复杂度决定
  4. 及时关闭资源 :使用try-with-resources处理IO相关的Stream
  5. 合理使用Optional :避免空指针异常

总结

JDK 8 的 Stream API 为集合操作提供了强劲的函数式编程能力,通过链式调用和惰性求值等特性,可以写出更简洁、易读、高效的代码。掌握 Stream API 对于现代 Java 开发至关重大。

免责声明:本文为用户发表,不代表网站立场,仅供参考,不构成引导等用途。 系统环境
相关推荐
首页
搜索
订单
购物车
我的