Collection对象功能增强

Stream

介绍

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

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

Stream 单向,只能遍历一次。

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

生成流

常用的几种方式

流的操作

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

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

部分内容出处