基础原理

Stream并发和分组

2019-01-19  本文已影响33人  shz_Minato

一 Stream的flatMap

 操作符定义

 函数签名:Stream<R> flatMap(Function<? super T, ? extends Stream<? extends R>> mapper)

R 是新流中元素的类型
T 是旧流中的元素的类型
Function的意义是:接收一个参数,返回一个结果。

连接起来就是:flatMap将旧流中类型为T的每个元素,转为一个新的子流,子流中元素的
类型是R,并将子流汇总为总流

旧流中有几个元素,就会有几个子流

 实例:将数组交叉输出

public class StreamTest {
    public static void main(String[] args) {
        //将每个stringList元素+integerList元素前缀输出
        List<Integer> integerList = Arrays.asList(1, 2, 3, 4);
        List<String> stringList = Arrays.asList("一", "二", "三", "四");

        integerList.stream()
                .flatMap(it->stringList.stream().map(item->it+" "+item))
                .forEach(System.out::println);

        //相当于子流是stringList元素加前缀输出
        
    }
}

二 Stream的并行流

 Stream支持并行和串行的操作,串行是单线程的比较耗时,并行时多线程运行,运行效率高。Stream并行的操作比较简单,就是在流中添加parallel()操作。
 以排序为例

public class StreamTest {
    public static void main(String[] args) {
       
        List<UUID> list = new ArrayList<>(5000000);
        for (int i = 0; i < 5000000; i++) {
            list.add(i, UUID.randomUUID());
        }


        long startTime= System.currentTimeMillis();
        list.stream()
                .sorted()
                .count();
        long endTime=System.currentTimeMillis();
        System.out.println((endTime-startTime));


        startTime= System.currentTimeMillis();
        list.stream()
                .parallel()//添加该操作符即可
                .sorted()
                .count();
        endTime=System.currentTimeMillis();
        System.out.println((endTime-startTime));
        
        //运行结果
        3698
        1401 //并行更加有效率

    }
}

三 Stream的分组和分区

 Stream的分组和分区,需要的操作符是collect
 操作符的签名:R collect(Collector<? super T, A, R> collector)

R 是返回结果的类型
T 流中元素的类型
A 累加器的类型

该操作的含义:使用collector对流中的元素进行聚合的操作,collector封装了
collect(Supplier, BiConsumer, BiConsumer)中的参数,用于重用收集策略,比如toList,和收集操作,比如分组和分区。

 Collector:聚合操作,将流中元素收集至一个可变的容器中(List,Map等)。常见的聚合操作有:将元素添加至集合,拼接字符串,常见的数字计算(求和、最值、均值)等,Collectors中有类似的工具类方法。
Collector功能的实现主要是通过四个抽象方法:
   supplier():创建容器结果
   accumulator():将元素添加至容器中
   combiner():将两个容器合二为一(并行时)
   supplier():可选的转换操作

 分组实现 Collectors的groupingBy方法

static <T, K, D, A, M extends Map<K, D>>
    Collector<T, ?, M> groupingBy(Function<? super T, ? extends K> classifier,
                                  Supplier<M> mapFactory,
                                  Collector<? super T, A, D> downstream) 
    
    参数介绍
        M 是返回结果的类型,是Map的子类。分组的结果是Map
        T 是流中元素的类型
        K 是结果Map的key的类型
        A 是结果value的类型
        D 是结果Map的value的容器结果类型
        
        classifier是将流中元素转为结果Map的key
        mapFactory是结果的map
        downstream是整理map的value,因为有可能是多级分组,所以也是Collector
        

 分组案例 将List<String> 按其长度分组

public class StreamTest {
    public static void main(String[] args) {


        List<String> stringList = Arrays.asList("Hello", "World", "Java", "I");

        TreeMap<Integer, List<String>> collect = stringList.stream()
                .collect(Collectors.groupingBy(
                        String::length,//key是字符串的长度
                        TreeMap::new,//结果是TreeMap
                        Collectors.toList()));//value是list
        System.out.println(collect);


    }
}

 分区实现 Collectors的partitioningBy方法
 分区是分组的特殊化,就是按照predicate分成两组而已

//任然上例为例,将长度改为长短。凡是长度小4的在一组,长度大于5的在另外一组

public class StreamTest {
    public static void main(String[] args) {


        List<String> stringList = Arrays.asList("Hello", "World", "Java", "I");

        Map<Boolean, List<String>> map = stringList.stream()
                .collect(Collectors.partitioningBy(
                        it -> it.length() > 4,//predicate的条件
                        Collectors.toList()
                ));
        System.out.println(map);


    }
}

上一篇下一篇

猜你喜欢

热点阅读