Collection对象功能增强
Stream
介绍
Stream 不是集合元素,不是数据结构,不保存数据,它是有关算法和计算的。
Stream可以理解为是高级的 Iterator,只要给出需要对其包含的元素执行什么操作,比如 “过滤掉长度大于 10 的字符串”、“获取每个字符串的首字母”等,Stream 会隐式地在内部进行遍历,做出相应的数据转换。
Stream 单向,只能遍历一次。
Stream 惰性,是 pull,区别于 RxJava 的 push。
生成流
常用的几种方式
Collection.stream()
Collection.parallelStream()
Arrays.stream(T array)
或Stream.of()
IntStream.range()
流的操作
- 中间:
map
( flatMap
、mapToInt
等)、 filter
、 distinct
、 sorted
、 peek
、 limit
、 skip
、 parallel
、 sequential
、 unordered
- 终结:
forEach
、 forEachOrdered
、 toArray
、 reduce
、 collect
、 min
、 max
、 count
、 anyMatch
、 allMatch
、 noneMatch
、 findFirst
、 findAny
、 iterator
- 短路:
anyMatch
、 allMatch
、 noneMatch
、 findFirst
、 findAny
、 limit
示例
// 获取已成年的学生
List<Student> list = students.stream()
.filter(it -> it.age > 18)
.collect(Collectors.toList());
// 计算前10个学生的平均年龄
double aveAge = students.stream()
.limit(10)
.collect(Collectors.averagingDouble(it -> it.age));
常用操作符
map
将当前元素转换为新的元素, 一对一映射
List<String> names = students.stream()
.map(Student::getName)
.collect(Collectors.toList());
flatMap
最底层元素抽出来放到一起,一对多映射
// 定义一个班级类
@Data
public class Class {
private String name;
private List<Student> students;
}
// 从多个Class中取出每一个的Student并放到一个List中
List<Student> students = classes.stream()
.flatMap(it -> it.getStudents().stream())
.collect(Collectors.toList());
filter
对每一项进行,通过测试的元素被留下来
List<Student> list = students.stream()
.filter(it -> it.age > 18)
.collect(Collectors.toList());
distinct
去重
List<String> distinctedNames = students.stream()
.map(Student::getName)
.distinct()
.collect(Collectors.toList());
sorted
排序,类似List.sort()
limit / skip
limit 返回 Stream 的前面 n 个元素,skip 则是扔掉前 n 个元素
List<String> names = students.stream()
.map(Student::getName)
.limit(10)
.skip(3)
.collect(Collectors.toList());
forEach
接收一个 Lambda ,每一个元素上执行该表达式,类似Iterable.forEach()
forEachOrdered
串行流时等同于forEach
,并行流时让元素保持原顺序
toArray
把List<T>
转为 T[]
Student[] array = stream
.filter(it -> it.age > 18)
.toArray(Student[]::new);
reduce
提供一个起始值(不写时默认0),然后依照运算规则,将 Stream 中的元素组合
// 求所有学员的年龄之和
int sum = students.stream()
.mapToInt(Student::getAge)
.reduce(0, (left, right) -> left+right);
count
当前 Stream 中元素的个数
match
- allMatch:全部元素符合传入的 predicate,返回 true
- anyMatch:只要有一个元素符合传入的 predicate,返回 true
- noneMatch:没有一个元素符合传入的 predicate,返回 true
find
- findFirst:返回 Stream 的第一个元素,或者是空(用 Optional 包装)
- findAny:串行流时等同于 findFirst,并行流时返回最先完成段的第一个元素(用 Optional 包装)
Collectors收集器
toList
所有元素放进 List 并返回
toSet
所有元素放进 Set 并返回
toMap
根据元素生成 Map<K, V>
,key 相同时会报错
Map<String, Integer> map = students.stream()
.collect(Collectors.toMap(Student::getName, Student::getAge));
groupingBy
根据元素分组,返回 Map<K, List<E>>
// 根据年龄分组
Map<Integer, List<Student>> map = students.stream()
.collect(Collectors.groupingBy(Student::getAge));
partitioningBy
讲元素分两组,返回 Map<Boolean, List<E>>
// 成年的一组,未成年的一组
Map<Boolean, List<Student>> map = students.stream()
.collect(Collectors.partitioningBy(it -> it.age > 18));
joining
类似于String.join()
students.stream()
.map(Student::getName)
.collect(Collectors.joining(",", "prefix", "suffix"));
averaging
求平均值
- averagingDouble
- averagingInt
- averagingLong
summing
求和
- summingDouble
- summingInt
- summingLong
summarizing
返回一个 SummaryStatistics,包含 sum, count, min, max, average 等
- summarizingDouble
- summarizingInt
- summarizingLong
并行流
利用 ForkJoinPool,充分利用多核cpu的优势,把一个任务拆分成多个小任务,把多个小任务放到多个处理器核心上并行执行,当多个小任务执行完成之后,再将这些执行结果合并起来。需要线程安全,谨慎使用。