Java Stream API
JDK8工具类引入新特性。java.util.stream.Stream
Stream
不是集合本身,而是对集合 / 数组等数据源的 “计算管道”,支持链式调用、惰性求值,可高效实现过滤、映射、聚合等操作,尤其适合大数据量处理。
假设存在数据源:List<User> users = Arrays.asList( new User("张三", 25, "北京"), new User("李四", 30, "上海"), new User("王五", 25, "北京") );
(User
含name
、age
、city
字段及 getter)
filter(Predicate)过滤北京的用户:users.stream().filter(user -> "北京".equals(user.getCity())).collect(Collectors.toList());
等价于:使用明确的 Predicate 对象
import java.util.function.Predicate;
import java.util.stream.Collectors;
Predicate<User> isFromBeijing = user -> "北京".equals(user.getCity());
List<User> beijingUsers = users.stream()
.filter(isFromBeijing)
.collect(Collectors.toList());
map(Function)提取所有用户的姓名:
List<User> users = Arrays.asList(...);
// 方式1: Lambda 表达式
List<String> names1 = users.stream()
.map(user -> user.getName()) // ← 这是Lambda表达式
.collect(Collectors.toList());
// 方式2: 方法引用 (推荐)
List<String> names2 = users.stream()
.map(User::getName) // ← 这是方法引用[★★是Lambda表达式的语法糖★★]
.collect(Collectors.toList());
// 方式3: 匿名类 (传统方式,不推荐)
List<String> names3 = users.stream()
.map(new Function<User, String>() {
@Override
public String apply(User user) {
return user.getName();
}
}) // ← 这是匿名类
.collect(Collectors.toList());
sorted(Comparator)按年龄升序排序:
users.stream().sorted(Comparator.comparingInt(User::getAge)).collect(Collectors.toList());
Comparator.comparingInt()这是一个静态工厂方法,用于创建基于整数字段的比较器:
Comparator.comparingInt(User::getAge)
- 接收一个
ToIntFunction
(从对象提取int值的函数) - 返回一个
Comparator<User>
,按提取的int值进行排序 - 默认是升序排序
等价于:
Comparator<User> byAge = new Comparator<User>() {
@Override
public int compare(User u1, User u2) {
return Integer.compare(u1.getAge(), u2.getAge());
}
};
List<User> sortedByAge = users.stream()
.sorted(byAge)
.collect(Collectors.toList());
多重排序:
// 先按年龄升序,年龄相同再按姓名升序
List<User> multiSorted = users.stream()
.sorted(Comparator.comparingInt(User::getAge)
.thenComparing(User::getName))
.collect(Collectors.toList());
collect(Collector)按城市分组(Map<String, List<User>>
):
Map<String, List<User>> usersByCity = users.stream()
.collect(Collectors.groupingBy(User::getCity));
Collectors.groupingBy()
: 根据指定的分类函数进行分组User::getCity
: 分组依据,按城市字段分组- 返回
Map<String, List<User>>
: 键是城市名,值是该城市的所有用户列表
// 按城市分组,然后统计每组的数量
Map<String, Long> countByCity = users.stream()
.collect(Collectors.groupingBy(User::getCity, Collectors.counting()));
// 按城市分组,然后提取每组的姓名列表
Map<String, List<String>> namesByCity = users.stream()
.collect(Collectors.groupingBy(User::getCity,
Collectors.mapping(User::getName, Collectors.toList())));
count()统计年龄≥28 的用户数:
long count = users.stream()
.filter(u -> u.getAge() >= 28)
.count();
findFirst()获取第一个满足条件的用户(返回Optional
):
Optional<User> firstUser = users.stream()
.filter(u -> u.getAge() == 25)
.findFirst();
import java.util.Optional;
public class FindFirstExample {
public static void main(String[] args) {
List<User> users = Arrays.asList(
new User("张三", 25, "北京"),
new User("李四", 30, "上海"),
new User("王五", 25, "北京"),
new User("赵六", 28, "上海")
);
// 查找第一个年龄为25的用户
Optional<User> firstUser = users.stream()
.filter(u -> u.getAge() == 25)
.findFirst();
// 处理Optional的几种方式
// 方式1: ifPresent (如果存在则执行操作)
firstUser.ifPresent(user ->
System.out.println("找到用户: " + user.getName()));
// 方式2: orElse (如果不存在返回默认值)
User result = firstUser.orElse(new User("默认用户", 0, "未知"));
System.out.println("结果用户: " + result.getName());
// 方式3: orElseGet (懒加载默认值)
User result2 = firstUser.orElseGet(() -> new User("懒加载用户", 0, "未知"));
// 懒加载默认值指的是:只有在真正需要的时候才创建或计算默认值,而不是预先创建好。这是一种性能优化策略,避免不必要的对象创建和计算开销。在大多数情况下,特别是当默认值的创建成本较高时,应该优先使用 orElseGet() 来获得更好的性能。只有在默认值非常简单且成本极低时,才使用 orElse()。
// 方式4: orElseThrow (如果不存在抛出异常)
try {
User result3 = firstUser.orElseThrow(() ->
new RuntimeException("用户不存在"));
} catch (Exception e) {
System.out.println(e.getMessage());
}
// 方式5: 直接获取值(不推荐,可能抛异常)
if (firstUser.isPresent()) {
User user = firstUser.get();
System.out.println("直接获取: " + user.getName());
}
}
}
打印:
users.forEach(System.out::println);
并行 Stream 示例:
// 并行计算所有用户的年龄总和(自动分配多线程)
int totalAge = users.parallelStream()
.mapToInt(User::getAge)
.sum();
分类:
Java-Backend
标签:
Java
版权申明
本文系作者 @xiin 原创发布在To Future$站点。未经许可,禁止转载。
暂无评论数据