Stream Api常用的案例汇总

简介

什么是 Stream? Stream(流)是一个来自数据源的元素队列并支持聚合操作

元素是特定类型的对象,形成一个队列。 Java中的Stream并不会存储元素,而是按需计算。 数据源 流的来源。 可以是集合,数组,I/O
channel, 产生器generator 等。 聚合操作 类似SQL语句一样的操作, 比如filter, map, reduce,
find, match, sorted等。 和以前的Collection操作不同, Stream操作还有两个基础的特征:

Pipelining: 中间操作都会返回流对象本身。 这样多个操作可以串联成一个管道, 如同流式风格(fluent style)。
这样做可以对操作进行优化, 比如延迟执行(laziness)和短路( short-circuiting)。 内部迭代:
以前对集合遍历都是通过Iterator或者For-Each的方式, 显式的在集合外部进行迭代, 这叫做外部迭代。
Stream提供了内部迭代的方式, 通过访问者模式(Visitor)实现。
生成流
在 Java 8 中, 集合接口有两个方法来生成流: stream() − 为集合创建串行流。 parallelStream() −
为集合创建并行流。

Stream的操作符大体上分为两种:中间操作符和终止操作符

中间操作符

对于数据流来说,中间操作符在执行制定处理程序后,数据流依然可以传递给下一级的操作符。

中间操作符包含8种(排除了parallel,sequential,这两个操作并不涉及到对数据流的加工操作):

map(mapToInt,mapToLong,mapToDouble)
转换操作符,把比如A->B,这里默认提供了转int,long,double的操作符。

flatmap(flatmapToInt,flatmapToLong,flatmapToDouble) 拍平操作比如把
int[]{2,3,4} 拍平 变成 2,3,4
也就是从原来的一个数据变成了3个数据,这里默认提供了拍平成int,long,double的操作符。

limit 限流操作,比如数据流中有10个 我只要出前3个就可以使用。

distint 去重操作,对重复元素去重,底层使用了equals方法。

filter 过滤操作,把不想要的数据过滤。

peek 挑出操作,如果想对数据进行某些操作,如:读取、编辑修改等。

skip 跳过操作,跳过某些元素。

sorted(unordered) 排序操作,对元素排序,前提是实现Comparable接口,当然也可以自定义比较器。

       /**
        * skip  limit 截断操作  从索引 值为 2开始 查询4个
        */

       List<Integer> asList = Arrays.asList(1, 3, 5, 7, 9);
       List<Integer> collect2 = asList.stream().skip(2).limit(4).collect(toList());

终止操作符

数据经过中间加工操作,就轮到终止操作符上场了;终止操作符就是用来对数据进行收集或者消费的,数据到了终止操作这里就不会向下流动了,终止操作符只能使用一次。

collect 收集操作,将所有数据收集起来,这个操作非常重要,官方的提供的Collectors 提供了非常多收集器,可以说Stream
的核心在于Collectors。

count 统计操作,统计最终的数据个数。

findFirst、findAny 查找操作,查找第一个、查找任何一个 返回的类型为Optional。

noneMatch、allMatch、anyMatch 匹配操作,数据流中是否存在符合条件的元素 返回值为bool 值。

min、max 最值操作,需要自定义比较器,返回数据流中最大最小的值。

reduce 规约操作,将整个数据流的值规约为一个值,count、min、max底层就是使用reduce。

forEach、forEachOrdered 遍历操作,这里就是对最终的数据进行消费了。

toArray 数组操作,将数据流的元素转换成数组。

实例

/**
 * 学生分数实体
 */
public class StuScore {
    public Integer id;//学生id
    private String name;//姓名
    public Integer classId;//班级id
    public String className;//班级名称
    public BigDecimal score1;//分数1  BigDecimal类型
    public Double score2;    //分数2  Double类型
}
    //学生分数列表
    private static List<StuScore>list=new ArrayList<>();
    static {
        StuScore c = null;
        for (int i = 10; i < 20; i++) {
            c = new StuScore();
            c.setId(i);
            c.setName(i + "name");
            c.setScore1(new BigDecimal(45 + i * 6));
            c.setScore2((double) (45 + i * 6));
            c.setClassId(2);
            c.setClassName("二班");
            list.add(c);
        }
        for (int i = 0; i < 10; i++) {
            c = new StuScore();
            c.setId(i);
            c.setName(i + "name");
            c.setScore1(new BigDecimal(40 + i * 5));
            c.setScore2((double) (40 + i * 5));
            c.setClassId(1);
            c.setClassName("一班");
            list.add(c);
        }

        Collections.sort(list, Comparator.comparing(StuScore::getId));//按照id升序
        Collections.reverse(list);//反转倒序
        Collections.reverse(list);//反转倒序
        System.out.println("============集合init数据==================");
        list.stream().forEach(t -> {
            System.out.println(t);
        });
        System.out.println("============集合init数据==================");
    }

初始化数据

==============================
==============================
StuScore{id=0, name=‘0name’, classId=1, className=‘一班’, score1=40, score2=40.0}
StuScore{id=1, name=‘1name’, classId=1, className=‘一班’, score1=45, score2=45.0}
StuScore{id=2, name=‘2name’, classId=1, className=‘一班’, score1=50, score2=50.0}
StuScore{id=3, name=‘3name’, classId=1, className=‘一班’, score1=55, score2=55.0}
StuScore{id=4, name=‘4name’, classId=1, className=‘一班’, score1=60, score2=60.0}
StuScore{id=5, name=‘5name’, classId=1, className=‘一班’, score1=65, score2=65.0}
StuScore{id=6, name=‘6name’, classId=1, className=‘一班’, score1=70, score2=70.0}
StuScore{id=7, name=‘7name’, classId=1, className=‘一班’, score1=75, score2=75.0}
StuScore{id=8, name=‘8name’, classId=1, className=‘一班’, score1=80, score2=80.0}
StuScore{id=9, name=‘9name’, classId=1, className=‘一班’, score1=85, score2=85.0}
StuScore{id=10, name=‘10name’, classId=2, className=‘二班’, score1=105, score2=105.0}
StuScore{id=11, name=‘11name’, classId=2, className=‘二班’, score1=111, score2=111.0}
StuScore{id=12, name=‘12name’, classId=2, className=‘二班’, score1=117, score2=117.0}
StuScore{id=13, name=‘13name’, classId=2, className=‘二班’, score1=123, score2=123.0}
StuScore{id=14, name=‘14name’, classId=2, className=‘二班’, score1=129, score2=129.0}
StuScore{id=15, name=‘15name’, classId=2, className=‘二班’, score1=135, score2=135.0}
StuScore{id=16, name=‘16name’, classId=2, className=‘二班’, score1=141, score2=141.0}
StuScore{id=17, name=‘17name’, classId=2, className=‘二班’, score1=147, score2=147.0}
StuScore{id=18, name=‘18name’, classId=2, className=‘二班’, score1=153, score2=153.0}
StuScore{id=19, name=‘19name’, classId=2, className=‘二班’, score1=159, score2=159.0}
==============================
==============================

分组


  Map> map1 = list.stream().collect(Collectors.groupingBy(Student::getSchoolId));


  Map> map2 = list.stream().collect(Collectors.groupingBy(Student::getSchoolId, Collectors.mapping(Student::getName, Collectors.toList())));

按照班级统计最大值,最小值,数量,总分,平均分

/**
         * 如果实体分数是Double类型
         */
        Map<Integer, Map<String, Object>> map1 = list.stream().collect(groupingBy(StuScore::getClassId, collectingAndThen(toList(), m -> {
            Map<String, Object> map = new LinkedHashMap<>();
            StuScore stuScore = m.stream().findAny().get();
            map.put("classId", stuScore.getClassId());
            map.put("className", stuScore.getClassName());
            map.put("min", m.stream().mapToDouble(StuScore::getScore2).min().getAsDouble());
            map.put("max", m.stream().mapToDouble(StuScore::getScore2).max().getAsDouble());
            map.put("count", m.stream().mapToDouble(StuScore::getScore2).count());
            map.put("sum", m.stream().mapToDouble(StuScore::getScore2).sum());
            map.put("average", m.stream().mapToDouble(StuScore::getScore2).average().getAsDouble());
            //上面单独求总数,数量以及平均数、下面直接统计上述所有
            map.put("statistics", m.stream().mapToDouble(StuScore::getScore2).summaryStatistics());
            return map;
        })));
        System.out.println("=========统计方法一============");
        map1.values().stream().forEach(t -> {
            System.out.println(t);
        });

=统计方法一====
{classId=1, className=一班, min=40.0, max=85.0, count=10, sum=625.0, average=62.5, statistics=DoubleSummaryStatistics{count=10, sum=625.000000, min=40.000000, average=62.500000, max=85.000000}}
{classId=2, className=二班, min=105.0, max=159.0, count=10, sum=1320.0, average=132.0, statistics=DoubleSummaryStatistics{count=10, sum=1320.000000, min=105.000000, average=132.000000, max=159.000000}}

按照班级统计最大值,最小值,数量,总分,平均分

        /**
         * 如果实体分数是BigDecimal类型
         */
        Map<Integer, Map<String, Object>> map2 = list.stream().collect(groupingBy(StuScore::getClassId, collectingAndThen(toList(), ms -> {
            Map<String, Object> map = new LinkedHashMap<>();
            StuScore stuScore = ms.stream().findAny().get();//取该流中的某个值
            map.put("classId", stuScore.getClassId());
            map.put("className", stuScore.getClassName());
            /**
             * reduce  循环计算
             */
            BigDecimal sums = ms.stream()
                    .map(StuScore::getScore1)
                    .reduce((x, y) -> x.add(y)).get();//总数
            long count = ms.stream().count();
            BigDecimal average = sums.divide(new BigDecimal(count));
            //正序排序;如果倒序排的话倒置;Comparator.comparing(StuScore::getScore1).reversed()
            List<StuScore> collect = ms.stream().sorted(Comparator.comparing(StuScore::getScore1)).collect(toList());
            BigDecimal min2 = ms.stream().map(StuScore::getScore1).min(BigDecimal::compareTo).get();
            BigDecimal max2 = ms.stream().map(StuScore::getScore1).max((o1, o2) -> o1.compareTo(o2)).get();

            map.put("min", collect.get(0).getScore1());
            map.put("max", collect.get(collect.size() - 1).getScore1());
            map.put("count", count);
            map.put("sum", sums);
            map.put("average", average);
            map.put("min2", min2);
            map.put("max2", max2);
            return map;
        })));


        System.out.println("==========统计方法二===========");
        map2.values().stream().forEach(t -> {
            System.out.println(t);
        });

统计方法二=
{classId=1, className=一班, min=40, max=85, count=10, sum=625, average=62.5, min2=40, max2=85}
{classId=2, className=二班, min=105, max=159, count=10, sum=1320, average=132, min2=105, max2=159}

实体去重

如果是包装类的集合可直接distinct()方法去重

        /**
         * 按照实体的某一个字段去重;也可以通过map 具体字段形成新的集合直接distinct()
         */
        ArrayList<StuScore> collect1 = list.stream().collect(
                collectingAndThen(
                        toCollection(() -> new TreeSet<>(Comparator.comparing(StuScore::getClassId))), ArrayList::new)
        );

        System.out.println("去重后的集合长度" + collect1.size());

去重后的集合长度2

聚合转换map,过滤filter

        /**
         * 聚合实体某一个字段形成新的集合
         */
        List<Double> collect = list.stream().map(StuScore::getScore2).collect(toList());
        /**filter 给定的条件进行过滤
         * 分数大于60分的学生集合
         */
        List<StuScore> collect4 = list.stream().filter(t -> t.getScore2() > 60).collect(toList());
        List<StuScore> collect5 = list.stream().filter(t -> t.getScore1().compareTo(new BigDecimal(60)) > -1).collect(toList());

Collections排序sort

        Collections.sort(list, Comparator.comparing(StuScore::getId));//按照id升序
        Collections.reverse(list);//反转倒序


stream 排序sorted

    /**
             * 正序排序;如果倒序排的话倒置;Comparator.comparing(StuScore::getScore1).reversed()
             */
            List<StuScore> collect = ms.stream().sorted(Comparator.comparing(StuScore::getScore1)).collect(toList());

其他操作

/**
     * 1.peek方法是消费型接口。 用于DEBUG
     * 调用peek方法后, 流还在。用于debug调试,不产生新的流,里面的方法没有执行
     * 可以进行流操作的时候,返回新的流
     *
     * foreach  直接消费掉,不返回新的流
     * peek为中间操作,foreach为终端操作。
     * peek执行体必须有终端语句才会被执行。
     *
     *
     * 2.map方法是函数型接口。
     * 调用map方法后,流已经被消费。
     */
    /** skip 跳过操作,跳过某些元素。
     * skip  limit 截断操作  从索引 值为 2开始 查询4个
     */
    System.out.println("============peek和foreach的操作============");
        asList.stream().peek(t -> {
            System.out.print(t);
        }).collect(Collectors.toList());
        System.out.println("\n==========================");
        asList.stream().forEach(t -> {
            System.out.print(t);
        });

peek和foreach的操作 13579
========================== 13579


        System.out.println("\n============map和flatMap===扁平化处理,处理字符串=============");

        /**
         * map对一位数组操作
         * flatMap 对二维数组操作  将二维数组数据聚合到一位数组进行操作
         */

        List<List<Integer>> lists = new ArrayList<>();
        List<Integer> list22 = new ArrayList<>();
        list22.add(2);
        list22.add(22);
        list22.add(222);
        lists.add(list22);
        List<Integer> list33 = new ArrayList<>();
        list33.add(33);
        lists.add(list33);
        System.out.println("===========flatMap扁平化处理======================");
        System.out.println(lists);

        List<Integer> collect3 = lists.stream().flatMap(Collection::stream).collect(toList());
        System.out.println(collect3);

map和flatMap=扁平化处理,处理字符串===
=flatMap扁平化处理============
[[2, 22, 222], [33]]
[2, 22, 222, 33]

你可能感兴趣的:(开发语言,java)