Java8 Stream完全使用指南
什么是Stream
Stream是Java 1.8版本开始提供的一个接口,主要提供对数据集合使用流的方式进行操作,流中的元素不可变且只会被消费一次,所有方法都设计成支持链式调用。使用Stream API可以极大生产力,写出高效率、干净、简洁的代码。
如何获得Stream实例
Stream提供了静态构建方法,可以基于不同的参数创建返回Stream实例
使用Collection的子类实例调用stream()或者parallelStream()方法也可以得到Stream实例,两个方法的区别在于后续执行Stream其他方法的时候是单线程还是多线程
1 | Stream<String> stringStream = Stream.of("1", "2", "3"); |
filter
filter方法用于根据指定的条件做过滤,返回符合条件的流
1 | Stream<Integer> numStream = Stream.of(-2, -1, 0, 1, 2, 3); |
map
map方法用于将流中的每个元素执行指定的转换逻辑,返回其他类型元素的流
1 | Stream<Integer> numStream = Stream.of(-2, -1, 0, 1, 2, 3); |
mapToInt mapToLong mapToDouble
这三个方法是对map方法的封装,返回的是官方为各个类型单独定义的Stream,该Stream还提供了适合各自类型的其他操作方法
1 | Stream<String> stringStream = Stream.of("-2", "-1", "0", "1", "2", "3"); |
flatMap
flatMap方法用于将流中的每个元素转换成其他类型元素的流,比如,当前有一个订单(Order)列表,每个订单又包含多个商品(itemList),如果要得到所有订单的所有商品汇总,就可以使用该方法
1 | Stream<Item> allItemStream = orderList.stream().flatMap(order -> order.itemList.stream()); |
flatMapToInt flatMapToLong flatMapToDouble
这三个方法是对flatMap方法的封装,返回的是官方为各个类型单独定义的Stream,使用方法同上
distinct
distinct方法用于对流中的元素去重,判断元素是否重复使用的是equals方法
1 | Stream<Integer> numStream = Stream.of(-2, -1, 0, 0, 1, 2, 2, 3); |
sorted
sorted有一个无参和一个有参的方法,用于对流中的元素进行排序。无参方法要求流中的元素必须实现Comparable接口,不然会报java.lang.ClassCastException异常
1 | Stream<Integer> unorderedStream = Stream.of(5, 6, 32, 7, 27, 4); |
有参方法sorted(Comparator<? super T> comparator)不需要元素实现Comparable接口,通过指定的元素比较器对流内的元素进行排序
1 | Stream<String> unorderedStream = Stream.of("1234", "123", "12", "12345", "123456", "1"); |
peek
peek方法可以不调整元素顺序和数量的情况下消费每一个元素,然后产生新的流,按文档上的说明,主要是用于对流执行的中间过程做debug的时候使用,因为Stream使用的时候一般都是链式调用的,所以可能会执行多次流操作,如果想看每个元素在多次流操作中间的流转情况,就可以使用这个方法实现
1 | Stream.of("one", "two", "three", "four") |
limit(long maxSize)
limit方法会对流进行顺序截取,从第1个元素开始,保留最多maxSize个元素
1 | Stream<String> stringStream = Stream.of("-2", "-1", "0", "1", "2", "3"); |
skip(long n)
skip方法用于跳过前n个元素,如果流中的元素数量不足n,则返回一个空的流
1 | Stream<String> stringStream = Stream.of("-2", "-1", "0", "1", "2", "3"); |
forEach
forEach方法的作用跟普通的for循环类似,不过这个可以支持多线程遍历,但是不保证遍历的顺序
1 | Stream<String> stringStream = Stream.of("-2", "-1", "0", "1", "2", "3"); |
forEachOrdered
forEachOrdered方法可以保证顺序遍历,比如这个流是从外部传进来的,然后在这之前调用过parallel方法开启了多线程执行,就可以使用这个方法保证单线程顺序遍历
1 | Stream<String> stringStream = Stream.of("-2", "-1", "0", "1", "2", "3"); |
toArray
toArray有一个无参和一个有参的方法,无参方法用于把流中的元素转换成Object数组
1 | Stream<String> stringStream = Stream.of("-2", "-1", "0", "1", "2", "3"); |
有参方法toArray(IntFunction<A[]> generator)支持把流中的元素转换成指定类型的元素数组
1 | Stream<String> stringStream = Stream.of("-2", "-1", "0", "1", "2", "3"); |
reduce
reduce有三个重载方法,作用是对流内元素做累进操作
第一个reduce(BinaryOperator
accumulator 为累进操作的具体计算
1 | Stream<Integer> numStream = Stream.of(-2, -1, 0, 1, 2, 3); |
第二个reduce(T identity, BinaryOperator
identity 为累进操作的初始值
accumulator 同上
1 | Stream<Integer> numStream = Stream.of(-2, -1, 0, 1, 2, 3); |
collect
主要作用是把流中的元素作为集合转换成其他Collection的子类,其内部实现类似于前面的累进操作
1 | Stream<Integer> numStream = Stream.of(-2, -1, 0, 1, 2, 3); |
min
min方法用于计算流内元素的最小值
1 | Stream<Integer> numStream = Stream.of(-2, -1, 0, 1, 2, 3); |
max
min方法用于计算流内元素的最大值
1 | Stream<Integer> numStream = Stream.of(-2, -1, 0, 1, 2, 3); |
count
count方法用于统计流内元素的总个数
1 | Stream<Integer> numStream = Stream.of(-2, -1, 0, 1, 2, 3); |
anyMatch
anyMatch方法用于匹配校验流内元素是否有符合指定条件的元素
1 | Stream<Integer> numStream = Stream.of(-2, -1, 0, 1, 2, 3); |
allMatch
noneMatch方法用于匹配校验流内元素是否都不符合指定条件
1 | Stream<Integer> numStream = Stream.of(-2, -1, 0, 1, 2, 3); |
findFirst
findFirst方法用于获取第一个元素,如果流是空的,则返回Optional.empty
1 | Stream<Integer> numStream = Stream.of(-2, -1, 0, 1, 2, 3); |
findAny
findAny方法用于获取流中的任意一个元素,如果流是空的,则返回Optional.empty,因为可能会使用多线程,所以不保证每次返回的是同一个元素
1 | Stream<Integer> numStream = Stream.of(-2, -1, 0, 1, 2, 3); |
多属性过滤
1 | List<SupplierEvaluationYear> filter = supEvaluationYearList.stream() |
根据部门进行分组,并获取汇总人数
1 | Map<String, Long> collect4 = inputForms.stream().collect(Collectors.groupingBy(InputForm::getCreateDeptName, Collectors.counting())); |
拼接某个字段的值,可以设置前缀,后缀或者分隔符
1 | String collect3 = inputForms.stream().map(InputForm::getCreateUserName).collect(Collectors.joining(",", "我是前缀", "我是后缀")); |
More info: MartinDai