1. 概述
Java 8 最令人兴奋的特性之一是 Stream API —— 简单来说,它是一个处理元素序列的强大工具。
StreamEx 是一个为标准 Stream API 提供额外功能库,同时优化了性能。核心特性包括:
✅ 更简洁便捷的日常操作实现 ✅ 100% 兼容原生 JDK Stream ✅ 并行处理友好:所有新特性都尽可能利用并行流优势 ✅ 高性能低开销:用更少代码解决问题时,性能不会劣于原生实现(有时甚至更快)
本教程将展示 StreamEx API 的部分核心功能。
2. 环境搭建
要使用 StreamEx,需要在 pom.xml
中添加依赖:
<dependency>
<groupId>one.util</groupId>
<artifactId>streamex</artifactId>
<version>0.6.5</version>
</dependency>
最新版本可在 Maven Central 获取。
本教程将使用简单的 User
类:
public class User {
int id;
String name;
Role role = new Role();
// 标准 getter/setter 和构造方法
}
以及 Role
类:
public class Role {
}
3. 收集器快捷方法
Stream 中最常用的终端操作之一是 collect
,用于将元素重新打包到指定集合中。但原生写法在简单场景下显得冗余:
users.stream()
.map(User::getName)
.collect(Collectors.toList());
3.1. 集合收集
StreamEx 无需显式提供 Collector
即可指定集合类型:
List<String> userNames = StreamEx.of(users)
.map(User::getName)
.toList();
⚠️ 当需要比简单收集更复杂的操作时,
collect
方法依然可用。
3.2. 高级收集器
groupingBy
的简写形式:
Map<Role, List<User>> role2users = StreamEx.of(users)
.groupingBy(User::getRole);
这会生成类似 SQL GROUP BY
的 Map 结构。原生写法需要:
Map<Role, List<User>> role2users = users.stream()
.collect(Collectors.groupingBy(User::getRole));
类似地,Collectors.joining()
也有简写:
StreamEx.of(1, 2, 3)
.joining("; "); // "1; 2; 3"
4. 元素增删与选择
当处理混合类型列表时,可按类型过滤:
List usersAndRoles = Arrays.asList(new User(), new Role());
List<Role> roles = StreamEx.of(usersAndRoles)
.select(Role.class)
.toList();
通过便捷操作在 Stream 首尾添加元素:
List<String> appendedUsers = StreamEx.of(users)
.map(User::getName)
.prepend("(none)")
.append("LAST")
.toList();
使用 nonNull()
过滤空值,并直接作为 Iterable 使用:
for (String line : StreamEx.of(users).map(User::getName).nonNull()) {
System.out.println(line);
}
5. 数学运算与原生类型支持
StreamEx 增强了对原生类型的支持,看这个自解释的例子:
short[] src = {1,2,3};
char[] output = IntStreamEx.of(src)
.map(x -> x * 5)
.toCharArray();
再比如计算无序 double
数组中相邻元素的差值:
public double[] getDiffBetweenPairs(double... numbers) {
return DoubleStreamEx.of(numbers)
.pairMap((a, b) -> b - a)
.toArray();
}
6. Map 操作
6.1. 按键过滤
通过 Map 创建 Stream 并按值过滤:
Map<String, Role> nameToRole = new HashMap<>();
nameToRole.put("first", new Role());
nameToRole.put("second", null);
Set<String> nonNullRoles = StreamEx.ofKeys(nameToRole, Objects::nonNull)
.toSet();
6.2. 键值对操作
通过 EntryStream
操作键值对:
public Map<User, List<Role>> transformMap(
Map<Role, List<User>> role2users) {
Map<User, List<Role>> users2roles = EntryStream.of(role2users)
.flatMapValues(List::stream)
.invert()
.grouping();
return users2roles;
}
EntryStream.of
将 Map 转换为键值流,flatMapValues
展开角色列表,invert
交换键值,最后 grouping
完成反转映射 —— 四步搞定复杂转换。
6.3. 键值映射
独立映射键和值:
Map<String, String> mapToString = EntryStream.of(users2roles)
.mapKeys(String::valueOf)
.mapValues(String::valueOf)
.toMap();
快速转换键值类型,简单粗暴。
7. 文件操作
StreamEx 支持高效文件处理(避免全文件加载),特别适合大文件:
StreamEx.ofLines(reader)
.remove(String::isEmpty)
.forEach(System.out::println);
⚠️ 重要:StreamEx 不会自动关闭文件!读写操作后务必手动关闭资源,避免内存泄漏。
8. 总结
本文介绍了 StreamEx 的核心功能,更多技巧可参考其速查表。
完整代码示例见 GitHub 仓库。