找不到有用的Stream文章?搜索全是处理数字数组或者字符串数字?实战干货,即贴即用
Collectors类:
Collector接口的实现,它实现了各种有用的缩减、操作,例如将元素累积到集合中、汇总、根据各种条件的元素等
能干什么
- 排序查找过滤
- 数据分组
- 数据分区
- 数据分组后,对每一个组进行缩减统计
- ···
JDK给的官方例子!
// 获取所有学生的名字,结果收集为List<String>
List<String> names= people.stream()
.map(Person::getName)
.collect(Collectors.toList());
// 获取所有学生的名字,结果收集为TreeSet
Set<String> set = people.stream()
.map(Person::getName)
.collect(Collectors.toCollection(TreeSet::new));
// 将元素转换为字符串并连接它们,用逗号分隔
String joined = things.stream()
.map(Object::toString)
.collect(Collectors.joining(","));
// 计算员工工资总额
int total = employees.stream()
.collect(Collectors.summingInt(Employee::getSalary)));
// 按部门分组的员工(上游按部门进行分组;下游不做处理,则是一个员工对象list)
Map<Department, List<Employee>> byDept = employees.stream()
.collect(Collectors.groupingBy(Employee::getDepartment));
// 按部门计算工资总额(上游按部门进行分组;下游求和int,返回Integer)
Map<Department, Integer> totalByDept = employees.stream()
.collect( Collectors.groupingBy(
Employee::getDepartment,
Collectors.summingInt(Employee::getSalary)));
// 将学生分为及格和不及格
Map<Boolean, List<Student>> passingFailing = students.stream()
.collect(Collectors.partitioningBy(s -> {
s.getGrade() >= PASS_THRESHOLD
}));
// 计算每个城市居民的最长姓氏(上游按城市分组,下游通过reducing,传入一个比较器返回名字最长的name)
Comparator<String> byLength = Comparator.comparing(String::length);
Map<City, String> longestLastNameByCity = people.stream()
.collect(groupingBy(
Person::getCity,
reducing(Person::getLastName, BinaryOperator.maxBy(byLength))
) );
// 计算每个城市中人们的姓氏集合(上游按城市分组,下游收集LastName并转换为Set)
Map<City, Set<String>> namesByCity = people.stream()
.collect(groupingBy(
Person::getCity,
mapping(Person::getLastName, toSet())
));
// 计算每个城市中人们的姓氏集,并按城市名排序(上游按城市分组,下游收集LastName并转换为Set,中间转为TreeMap)
Map<City, Set<String>> namesByCity = people.stream()
.collect( groupingBy(
Person::getCity,
TreeMap::new,
mapping(Person::getLastName, toSet())
));
ConcurrentMap<City, Set<String>> namesByCity = people.stream()
.collect(groupingBy(
Person::getCity,
ConcurrentSkipListMap::new,
mapping(Person::getLastName, toSet())
));
// 将学生与他们的平均成绩进行比较
Map<Student, Double> studentToGPA = students.stream()
.collect(toMap(
Functions.identity(),
student -> computeGPA(student)
));
// 将唯一标识符映射到学生
Map<String, Student> studentIdToStudent = students.stream()
.collect(toMap(
Student::getId,
Functions.identity()
));
// 将名称映射到连接的地址列表
Map<String, String> phoneBook = people.stream()
.collect(toMap(
Person::getName,
Person::getAddress,
(s, a) -> s + ", " + a))
);
Collectors静态方法介绍:
- 转换
// 转换为Collection
toCollection(Supplier<C> collectionFactory);
// 转换为List
toList();
// 转换为Set
toSet();
- 拼接
// 通过StringBuilder拼接,返回String
joining();
// 指定拼接的 分隔符
joining(CharSequence delimiter);
// 指定拼接的 分隔符 开始 和结尾(类似 mybatis 的 separator=',' open='(' close=')' )
joining(CharSequence delimiter, CharSequence prefix, CharSequence suffix));
- 映射
mapMerger();
// 将接受类型元素的Collector改编为接受T类型元素的Collector,mapper 应用于输入元素的函数,downstream 接受映射值的收集器
mapping(Function<? super T, ? extends U> mapper,Collector<? super U, A, R> downstream);
- 数学计算
// 统计元素的数量,如果不存在任何元素,则结果为0
counting();
// 根据给定的比较器 Comparator 生成最小元素
minBy(Comparator<? super T> comparator);
// 根据给定的比较器Comparator生成最大元素
maxBy(Comparator<? super T> comparator);
// 求和:没有元素参与计算,返回0
summingInt(ToIntFunction<? super T> mapper);
summingLong(ToLongFunction<? super T> mapper);
summingDouble(ToDoubleFunction<? super T> mapper);
//求平均:返回double类型或者0.0d;没有元素参与计算,返回0
averagingInt(ToIntFunction<? super T> mapper);
averagingLong(ToLongFunction<? super T> mapper);
averagingDouble(ToDoubleFunction<? super T> mapper);
- reduce
// 元素缩减:常用于下游的多级约简中使用
reducing(BinaryOperator<T> op);
reducing(T identity, BinaryOperator<T> op);
reducing(U identity, Function<? super T, ? extends U> mapper, BinaryOperator<U> op);
- 分组,根据分类函数对元素进行分组,返回Map
// 直接分组
groupingBy(Function);
// 分组后,下游可以对 “集合” 执行操作
groupingBy(Function, Collector);
// 分组后,下游可以对 “集合” 执行操作,并且转换为mapFactory
groupingBy(Function, Supplier, Collector);
使用groupingByConcurrent可以提供更好的并行性能
groupingByConcurrent(Function);
groupingByConcurrent(Function, Collector);
groupingByConcurrent(Function, Supplier, Collector);
- 分区
// 直接分区
partitioningBy(Function);
// 分区后,下游可以对 “集合” 执行操作
partitioningBy(Function, Collector);
- 手动转为Map,使用map.merge(key,value,function,T)
映射指定的key和value
toMap(Function, Function);
toMap(Function, Function, BinaryOperator);
toMap(keyMapper, valueMapper, BinaryOperator, Supplier);
// 使用toConcurrentMap可以提供更好的并行性能
toConcurrentMap();
toConcurrentMap();
toConcurrentMap();
- 其它
summarizingInt();
summarizingLong();
summarizingDouble();
collectingAndThen();
基本概念:什么是 Stream?
Stream(流)是一个来自数据源的元素队列并支持聚合操作
- 元素是特定类型的对象,形成一个队列。 Java中的Stream并不会存储元素,而是按需计算。
- 数据源 流的来源。 可以是集合,数组,I/O channel, 产生器generator 等。
- 聚合操作 类似SQL语句一样的操作, 比如filter, map, reduce, find, match, sorted等。
和以前的Collection操作不同, Stream操作还有两个基础的特征:
- Pipelining: 中间操作都会返回流对象本身。 这样多个操作可以串联成一个管道, 如同流式风格(fluent style)。 这样做可以对操作进行优化, 比如延迟执行(laziness)和短路( short-circuiting)。
- 内部迭代: 以前对集合遍历都是通过Iterator或者For-Each的方式, 显式的在集合外部进行迭代, 这叫做外部迭代。 Stream提供了内部迭代的方式, 通过访问者模式(Visitor)实现。
生成流
在 Java 8 中, 集合接口有两个方法来生成流:
- stream() − 为集合创建串行流。
- parallelStream() − 为集合创建并行流。