Collection对象功能增强

Stream

介绍

Stream 不是集合元素,不是数据结构,不保存数据,它是有关算法和计算的。

Stream可以理解为是高级的 Iterator,只要给出需要对其包含的元素执行什么操作,比如 “过滤掉长度大于 10 的字符串”、“获取每个字符串的首字母”等,Stream 会隐式地在内部进行遍历,做出相应的数据转换。

Stream 单向,只能遍历一次。

Stream 惰性,是 pull,区别于 RxJava 的 push。

生成流

常用的几种方式

流的操作

map ( flatMapmapToInt 等)、 filterdistinctsortedpeeklimitskipparallelsequentialunordered

forEachforEachOrderedtoArrayreducecollectminmaxcountanyMatchallMatchnoneMatchfindFirstfindAnyiterator

anyMatchallMatchnoneMatchfindFirstfindAnylimit

示例

// 获取已成年的学生
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

find

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

求平均值

summing

求和

summarizing

返回一个 SummaryStatistics,包含 sum, count, min, max, average 等

并行流

利用 ForkJoinPool,充分利用多核cpu的优势,把一个任务拆分成多个小任务,把多个小任务放到多个处理器核心上并行执行,当多个小任务执行完成之后,再将这些执行结果合并起来。需要线程安全,谨慎使用。

部分内容出处