Java进阶学习之Stream流的基本概念以及使用技巧

一、Stream流的核心概念

什么是Stream流

  • Java 8引入的函数式数据处理API,用于高效操作集合(Collection)、数组等数据源
  • 不是数据结构,不存储数据,而是通过管道操作处理数据源
  • 支持链式调用惰性求值(Lazy Evaluation)

核心特点

  • 无存储:不修改原始数据源
  • 函数式风格:支持Lambda表达式
  • 延迟执行:中间操作不会立即执行
  • 可消费性:流只能被使用一次
  • 声明式:更关注"做什么"而非"如何做"
  • 链式调用:通过方法链组合多个操作

Stream的组成

  1. 数据源:集合、数组、I/O资源等
  2. 中间操作:过滤、映射、排序等(返回新的Stream)
  3. 终端操作:触发计算并产生结果(如collect、forEach等)

操作类型

类型 方法示例 特点
中间操作 filter(), map(), sorted() 返回新Stream,可链式调用
终止操作 forEach(), collect(), count() 触发计算,流被消耗

二、Stream流使用全流程

1.Stream流的创建

从集合创建
java 复制代码
List<String> list = Arrays.asList("a", "b", "c");
Stream<String> streamFromList = list.stream();
从数组创建
java 复制代码
String[] array = {"a", "b", "c"};
Stream<String> streamFromArray = Arrays.stream(array);
直接创建
java 复制代码
Stream<String> directStream = Stream.of("a", "b", "c");

2.常用中间操作

操作 说明 示例
filter() 条件过滤 .filter(s -> s.contains("a"))
map() 元素转换 .map(String::length)
flatMap() 扁平化转换(合并流) .flatMap(list -> list.stream())
distinct() 去重 .distinct()
sorted() 排序 .sorted(Comparator.reverseOrder())
peek() 调试用(不修改元素) .peek(System.out::println)
过滤和限制
java 复制代码
List<String> names = Arrays.asList("Alice", "Bob", "Charlie", "David");

// 过滤以"A"开头的名字
List<String> result = names.stream()
    .filter(name -> name.startsWith("A"))
    .collect(Collectors.toList()); // [Alice]

// 限制返回数量
List<String> limited = names.stream()
    .limit(2)
    .collect(Collectors.toList()); // [Alice, Bob]
映射
java 复制代码
List<String> words = Arrays.asList("Java", "Stream", "API");

// 转换为字符串长度
List<Integer> lengths = words.stream()
    .map(String::length)
    .collect(Collectors.toList()); // [4, 6, 3]

// 扁平化流(flatMap)
List<List<String>> nestedList = Arrays.asList(
    Arrays.asList("a", "b"),
    Arrays.asList("c", "d")
);

List<String> flatList = nestedList.stream()
    .flatMap(List::stream)
    .collect(Collectors.toList()); // [a, b, c, d]
排序
java 复制代码
List<String> names = Arrays.asList("John", "Alice", "Bob", "Charlie");

// 自然排序
List<String> sorted = names.stream()
    .sorted()
    .collect(Collectors.toList()); // [Alice, Bob, Charlie, John]

// 自定义排序
List<String> customSorted = names.stream()
    .sorted((s1, s2) -> s2.compareTo(s1))
    .collect(Collectors.toList()); // [John, Charlie, Bob, Alice]
去重
java 复制代码
List<Integer> numbers = Arrays.asList(1, 2, 2, 3, 3, 4);
List<Integer> distinct = numbers.stream()
    .distinct()
    .collect(Collectors.toList()); // [1, 2, 3, 4]

3.常用终止操作

操作 说明 示例
forEach() 遍历 .forEach(System.out::println)
collect() 转换为集合 .collect(Collectors.toList())
toArray() 转换为数组 .toArray(String[]::new)
reduce() 聚合计算 .reduce(0, Integer::sum)
min()/max() 极值查找 .max(Comparator.naturalOrder())
count() 计数 .count()
anyMatch() 任意元素匹配 .anyMatch(s -> s.startsWith("A"))
收集结果
java 复制代码
List<String> collected = Stream.of("a", "b", "c")
    .collect(Collectors.toList()); // [a, b, c]

Set<String> collectedSet = Stream.of("a", "b", "c")
    .collect(Collectors.toSet()); // [a, b, c] (顺序可能不同)

String joined = Stream.of("a", "b", "c")
    .collect(Collectors.joining(", ")); // "a, b, c"
遍历
java 复制代码
Stream.of("a", "b", "c")
    .forEach(System.out::println); // 打印每个元素
匹配
java 复制代码
boolean anyStartsWithA = Stream.of("apple", "banana", "apricot")
    .anyMatch(s -> s.startsWith("a")); // true

boolean allStartsWithA = Stream.of("apple", "apricot", "avocado")
    .allMatch(s -> s.startsWith("a")); // true

boolean noneStartsWithZ = Stream.of("apple", "banana", "cherry")
    .noneMatch(s -> s.startsWith("z")); // true

四、实战技巧与最佳实践

避免嵌套循环

java 复制代码
// 传统方式
for (Order order : orders) {
    for (Item item : order.getItems()) {
        if (item.isActive()) {
            activeItems.add(item);
        }
    }
}

// Stream优化
List<Item> activeItems = orders.stream()
    .flatMap(order -> order.getItems().stream())
    .filter(Item::isActive)
    .collect(Collectors.toList());

并行流加速处理

java 复制代码
long count = largeList.parallelStream()  // 使用多核并行处理
    .filter(obj -> obj.getValue() > 100)
    .count();

短路优化性能

java 复制代码
boolean hasAdmin = users.stream()
    .anyMatch(user -> "admin".equals(user.getRole()));  // 找到即终止

分组与分区

java 复制代码
// 按年龄分组
Map<Integer, List<Person>> ageGroups = people.stream()
    .collect(Collectors.groupingBy(Person::getAge));

// 分区:年龄是否>=18
Map<Boolean, List<Person>> adults = people.stream()
    .collect(Collectors.partitioningBy(p -> p.getAge() >= 18));

自定义收集器

java 复制代码
// 拼接字符串
String joined = stream.collect(Collectors.joining(", ", "[", "]"));

通过掌握Stream API,可使代码简洁性提升50%+,同时利用并行流可大幅提升大数据处理效率。重点理解操作链的惰性求值特性流的一次性消费原则,避免常见陷阱。

相关推荐
Forward♞9 分钟前
Qt——实现”Hello World“、认识对象树与Qt坐标系
开发语言·qt
草莓熊Lotso11 分钟前
《吃透 C++ 类和对象(中):拷贝构造函数与赋值运算符重载深度解析》
开发语言·c++·经验分享·笔记·其他
楚Y6同学20 分钟前
QT之键盘控制虚拟遥控系统开发总结
开发语言·c++·qt·串口通信
zyd091534 分钟前
代码随想录Day50:图论(图论理论、深度搜索理论、所有可达路径、广度搜索理论)
java·数据结构·算法·leetcode·图论
sswithyou39 分钟前
Socket 套接字的学习--UDP
网络协议·学习·udp
都叫我大帅哥1 小时前
Flink Slot 终极指南:从入门到避坑,幽默解析分布式计算的“工位经济学
java·大数据·flink
小凡敲代码1 小时前
2025年最新Java后端场景面试题(大厂真题+解析)
java·程序员·java面试·java面试题·后端开发·java场景题·2025求职面试
一百天成为python专家1 小时前
OpenCV图像平滑处理方法详解
开发语言·人工智能·python·opencv·机器学习·支持向量机·计算机视觉
软测进阶1 小时前
【Python】Python 函数基本介绍(详细版)
开发语言·python
摇滚侠1 小时前
面试实战 问题三十二 Java中创建对象的几种方式
java·面试·职场和发展