侧边栏壁纸
  • 累计撰写 67 篇文章
  • 累计创建 28 个标签
  • 累计收到 21 条评论

目 录CONTENT

文章目录

Java Stream API实战教程

Administrator
2026-03-21 / 0 评论 / 0 点赞 / 0 阅读 / 0 字 / 正在检测是否收录...
温馨提示:
部分素材来自网络,若不小心影响到您的利益,请联系我们删除。

Java Stream API是Java 8引入的最重要的新特性之一,它提供了一种声明式的方式来处理集合数据。本文将深入讲解Stream API的核心概念、常用操作和实战案例,助你写出更优雅、更高效的代码。

一、Stream API核心概念

Stream API是什么?简单来说,它是一个来自数据源的元素队列,支持顺序和并行聚合操作。与传统集合不同,Stream不存储数据,而是通过管道操作对数据进行计算。

Stream的特点

  1. 不存储数据: Stream不是数据结构,不存储元素
  2. 不可变性: Stream操作不会修改数据源
  3. 惰性求值: 中间操作不会立即执行,只有终止操作才会触发
  4. 可以并行: Stream支持并行处理,充分利用多核CPU

Stream vs 传统集合

// 传统方式:遍历List过滤
List<String> result = new ArrayList<>();
for (String str : names) {
    if (str.startsWith("J")) {
        result.add(str);
    }
}

// Stream方式:声明式编程
List<String> result = names.stream()
    .filter(str -> str.startsWith("J"))
    .collect(Collectors.toList());

二、Stream的创建方式

1. 从集合创建

List<String> list = Arrays.asList("Java", "Stream", "API");
Stream<String> stream = list.stream();

2. 从数组创建

String[] array = {"Java", "Stream", "API"};
Stream<String> stream = Arrays.stream(array);

3. 使用Stream.of()

Stream<String> stream = Stream.of("Java", "Stream", "API");

4. 使用Stream.generate()

// 生成无限流
Stream<Double> randomStream = Stream.generate(Math::random).limit(10);

5. 使用Stream.iterate()

// 生成序列流
Stream<Integer> stream = Stream.iterate(0, n -> n + 2).limit(10);

三、Stream常用操作详解

3.1 中间操作(Intermediate Operations)

filter - 过滤元素

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

// 筛选偶数
List<Integer> evenNumbers = numbers.stream()
    .filter(n -> n % 2 == 0)
    .collect(Collectors.toList());
// 结果: [2, 4, 6]

map - 转换元素

List<String> names = Arrays.asList("java", "stream", "api");

// 转换为大写
List<String> upperNames = names.stream()
    .map(String::toUpperCase)
    .collect(Collectors.toList());
// 结果: ["JAVA", "STREAM", "API"]

flatMap - 扁平化映射

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

// 扁平化为单个List
List<String> flattened = nestedList.stream()
    .flatMap(List::stream)
    .collect(Collectors.toList());
// 结果: ["a", "b", "c", "d"]

distinct - 去重

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

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

sorted - 排序

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

// 自然排序
List<Integer> sorted = numbers.stream()
    .sorted()
    .collect(Collectors.toList());

// 自定义排序
List<Integer> descSorted = numbers.stream()
    .sorted((a, b) -> b.compareTo(a))
    .collect(Collectors.toList());

limit - 截断

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

// 取前3个
List<Integer> first3 = numbers.stream()
    .limit(3)
    .collect(Collectors.toList());
// 结果: [1, 2, 3]

skip - 跳过

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

// 跳过前3个
List<Integer> afterSkip = numbers.stream()
    .skip(3)
    .collect(Collectors.toList());
// 结果: [4, 5, 6]

3.2 终止操作(Terminal Operations)

forEach - 遍历

List<String> names = Arrays.asList("Java", "Stream", "API");

names.stream()
    .forEach(name -> System.out.println(name));

collect - 收集结果

List<String> names = Arrays.asList("Java", "Stream", "API");

// 收集为List
List<String> list = names.stream()
    .collect(Collectors.toList());

// 收集为Set
Set<String> set = names.stream()
    .collect(Collectors.toSet());

// 收集为Map
Map<String, Integer> map = names.stream()
    .collect(Collectors.toMap(
        name -> name,
        String::length
    ));

reduce - 归约

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

// 求和
int sum = numbers.stream()
    .reduce(0, Integer::sum);
// 结果: 15

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

count - 计数

List<String> names = Arrays.asList("Java", "Stream", "API");

long count = names.stream()
    .filter(name -> name.startsWith("J"))
    .count();
// 结果: 1

anyMatch / allMatch / noneMatch - 匹配

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

// 是否存在偶数
boolean hasEven = numbers.stream()
    .anyMatch(n -> n % 2 == 0);

// 是否全部为正数
boolean allPositive = numbers.stream()
    .allMatch(n -> n > 0);

四、实战案例

案例1: 处理用户数据

class User {
    private String name;
    private int age;
    private String city;
    // getter和setter
}

List<User> users = Arrays.asList(
    new User("张三", 25, "北京"),
    new User("李四", 30, "上海"),
    new User("王五", 28, "北京")
);

// 查找北京的用户
List<String> beijingUsers = users.stream()
    .filter(user -> "北京".equals(user.getCity()))
    .map(User::getName)
    .collect(Collectors.toList());

// 按年龄分组
Map<Integer, List<User>> usersByAge = users.stream()
    .collect(Collectors.groupingBy(User::getAge));

案例2: 统计单词频率

String text = "Java Stream API is powerful Stream API makes code elegant";

Map<String, Long> wordCount = Arrays.stream(text.split(" "))
    .collect(Collectors.groupingBy(
        word -> word,
        Collectors.counting()
    ));

案例3: 数值操作

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

// 计算平均值
double average = numbers.stream()
    .mapToInt(Integer::intValue)
    .average()
    .orElse(0);

// 查找最大值
int max = numbers.stream()
    .mapToInt(Integer::intValue)
    .max()
    .orElse(0);

// 求和
int sum = numbers.stream()
    .mapToInt(Integer::intValue)
    .sum();

五、并行Stream(Parallel Stream)

并行Stream可以利用多核CPU提升性能:

List<Integer> largeList = ...; // 大数据集

// 顺序流
long sequentialTime = measureTime(() -> {
    largeList.stream()
        .filter(n -> n % 2 == 0)
        .count();
});

// 并行流
long parallelTime = measureTime(() -> {
    largeList.parallelStream()
        .filter(n -> n % 2 == 0)
        .count();
});

注意: 并行流适合数据量大、计算密集的场景,小数据集可能更慢。

六、Stream最佳实践

1. 避免空指针

// 不好的做法
list.stream().forEach(...); // 可能为null

// 好的做法
Optional.ofNullable(list)
    .orElse(Collections.emptyList())
    .stream()
    .forEach(...);

2. 使用方法引用

// 不好的做法
names.stream().map(name -> name.toUpperCase());

// 好的做法
names.stream().map(String::toUpperCase);

3. 合并操作

// 不好的做法
Stream<String> stream = names.stream();
stream = stream.filter(...);
stream = stream.map(...);

// 好的做法
names.stream()
    .filter(...)
    .map(...)
    .collect(...);

4. 注意性能

  • 避免在lambda中修改外部变量
  • 大数据集考虑使用parallelStream
  • 复杂操作考虑使用传统循环

七、常见问题

Q1: Stream和Iterator有什么区别?

A: Stream是Java 8的新特性,支持声明式编程、惰性求值、并行处理;Iterator是传统的迭代方式,需要手动管理。

Q2: Stream操作后还能再次使用吗?

A: 不能。Stream只能消费一次,再次使用会抛出IllegalStateException。

Q3: 并行Stream一定比顺序Stream快吗?

A: 不一定。小数据集、简单操作,并行Stream可能更慢。

八、总结

Java Stream API是现代Java开发的必备技能,它让代码更简洁、更易读。掌握Stream API的关键是:

  1. 理解中间操作和终止操作的区别
  2. 熟练使用常用操作方法
  3. 在实际项目中灵活应用
  4. 注意性能和最佳实践

持续练习和实践,你会发现Stream API的魅力所在!


相关阅读:

0

评论区