美文网首页
Java8新特性系列--流处理

Java8新特性系列--流处理

作者: 清风徐来水波不清 | 来源:发表于2018-08-31 13:04 被阅读0次

    之前博文有关于Java8新特性介绍,但是内容过于简单,实例太少,遂准备做一个Java8新特性系列,目的是和大家一起分享学习java8的乐趣,提升工作效率。这个系列是流处理系列,我会以实际案例由浅及深介绍流处理的使用。

    Stream简介

    Java8中的Stream是对与集合对象有所加强的新特性,专注于集合对象进行各种非常便利,高效的聚合操作,同时提供串行与并行两种模式的汇聚操作,使用了fork/join并行方式来拆分任务、加速处理过程。注意,这里的stream与原先的文件I/O流没有必然关系,是在Java8中的新内容。

    Stream有时类似于一个迭代器,但是相比原来的Iterator串行命令式的执行过程,stream通过并行方式去便利,遍历时stream数据会被分成多段,其中每一段都在不同的线程中进行处理,然后归并统一。

     List<String> list = new ArrayList<>();
     Stream<String> stream = list.stream();// 取流方式
    

    准备

    现提供一个简单的pojo类-Person.class

    class Person{
            String  name;
            String  com;
            Integer age;
            Integer house;
    
            public Person(String name, String com, Integer age, Integer house) {
                this.name = name;
                this.com = com;
                this.age = age;
                this.house = house;
            }
    
            public Integer getHouse() {
                return house;
            }
    
            public void setHouse(Integer house) {
                this.house = house;
            }
    
            public Person() {
            }
    
            public Person(String name, Integer age) {
                this.name = name;
                this.age = age;
            }
    
            public Person(String name, String com, Integer age) {
                this.name = name;
                this.com = com;
                this.age = age;
            }
    
            public String getCom() {
                return com;
            }
    
            public void setCom(String com) {
                this.com = com;
            }
    
            public String getName() {
                return name;
            }
    
            public void setName(String name) {
                this.name = name;
            }
    
            public Integer getAge() {
                return age;
            }
    
            public void setAge(Integer age) {
                this.age = age;
            }
    
            @Override
            public boolean equals(Object o) {
                if (this == o) return true;
                if (o == null || getClass() != o.getClass()) return false;
                DecryptData.Person person = (DecryptData.Person) o;
                return Objects.equals(name, person.name) &&
                        Objects.equals(age, person.age);
            }
    
            @Override
            public int hashCode() {
    
                return Objects.hash(name, age);
            }
        }
    

    PK 传统方式vs新特性

    简单介绍后,想必也很难理解概念性的东西,我们一步一步做简单的案例对比传统方式和新特性方式
    1.集合遍历

      @Test // 遍历集合
        public void testName() throws Exception {
    
            List<Person> peoples = new ArrayList<>(Arrays.asList(
                    new Person("name1",12),
                    new Person("name2",13),
                    new Person("name2",14),
                    new Person("name3",15)
                    ));
            // 传统增强for
            for (Person people : peoples) {
                System.out.println(people.getName());
            }
            // 新特性ForEach
            peoples.forEach(people-> System.out.println(people.getName()));
    
        }
    

    2.查找年龄大于18的人员

      @Test
        public void filterAge() throws Exception {
    
            List<Person> peoples = new ArrayList<>(Arrays.asList(
                    new Person("name1",12),
                    new Person("name2",13),
                    new Person("name3",33),
                    new Person("name4",21),
                    new Person("name1",22),
                    new Person("name2",15)
            ));
            // 传统过滤
            List<Person> ps=new ArrayList<>();
            for (Person people : peoples) {
                if (people.getAge()>18){
                    ps.add(people);
                }
            }
            System.err.println(JSON.toJSONString(ps));
            // 新特性过滤
            List<Person> collect = peoples.stream().filter(person -> person.getAge() > 18).collect(toList());
            System.err.println(JSON.toJSONString(collect));
    
        }
    

    结果:

    [{"age":33,"name":"name3"},{"age":21,"name":"name4"},{"age":22,"name":"name1"}]
    [{"age":33,"name":"name3"},{"age":21,"name":"name4"},{"age":22,"name":"name1"}]
    

    传统方式需要我们去遍历判断代码量很多,流处理方式直接使用过滤器filter,像查询数据库一样对查询过滤。Stream完胜!

    1. 过滤获取属性
      有时候我只想要获取姓名的集合并不想要所有person对象,那么在pk一下
      @Test
        public void filterFailed() throws Exception {
    
            List<Person> peoples = new ArrayList<>(Arrays.asList(
                    new Person("name1",12),
                    new Person("name2",13),
                    new Person("name3",33),
                    new Person("name4",21),
                    new Person("name1",22),
                    new Person("name2",15)
            ));
            // 传统增强for
            List<String> names=new ArrayList<>();
            for (Person people : peoples) {
                    names.add(people.getName());
            }
            System.err.println(JSON.toJSONString(names));
            // 新特性ForEach
            List<String> collect = peoples.stream().map(Person::getName).collect(toList());
            System.err.println(JSON.toJSONString(collect));
    
        }
    

    结果:

    ["name1","name2","name3","name4","name1","name2"]
    ["name1","name2","name3","name4","name1","name2"]
    

    同filter一样的道理,在代码量上可是减少了很多的代码。Stream胜出!
    4.分组统计
    那么问题来了,就上面几种优势也不是很明显啊,那么我们就来再看看两者的差距

     @Test
        public void statistic() throws Exception {
            // 统计每个人房子数量
            List<String> list = new ArrayList<>();
            Stream<String> stream = list.stream();
    
            List<Person> peoples = new ArrayList<>(Arrays.asList(
                    new Person("思聪","杭州",19,50),
                    new Person("马云","北京",50,100),
                    new Person("思聪","北京",19,20),
                    new Person("温州大婶","西安",1,120),
                    new Person("温州大婶","杭州",1,100),
                    new Person("我",null,18,0),
                    new Person("温州大婶","新西兰",1,200)
            ));
            // 传统增强for 统计
            List<Integer> sum =new ArrayList<>();
            for (Person people : peoples) {
                   //人生如此艰难,我还要继续。。。此处省略
            }
            System.err.println(JSON.toJSONString(sum));
    
            // 新特性ForEach
            Map<String, IntSummaryStatistics>  map=  peoples.stream().collect(groupingBy(Person::getName,summarizingInt(Person::getHouse)));
    
            System.err.println(JSON.toJSONString(map));
    
        }
    

    结果 :


    image.png

    没有对比哪来的伤害啊,传统敲代码的我完败。。。。

    1. 坑点
      注意:流操作一个流只能进行一次处理操作,像下面这个的做法就会出现问题。
       List<Person> peoples = new ArrayList<>(Arrays.asList(
                    new Person("思聪","杭州",19,50),
                    new Person("马云","北京",50,100),
                    new Person("思聪","北京",19,20),
                    new Person("温州大婶","西安",1,120),
                    new Person("温州大婶","杭州",1,100),
                    new Person("我",null,18,0),
                    new Person("温州大婶","新西兰",1,200)
            ));
    
            //+++++ 坑点+++++
            Stream<Person> stream = peoples.stream();
            List<String> collect = stream.map(Person::getName).collect(toList()); // 第一次使用 stream
            List<Person> collect1 = stream.filter(person -> person.getAge() > 18).collect(toList());// 第二次使用 stream
    
            System.out.println();
    

    异常:
    java.lang.IllegalStateException: stream has already been operated upon or closed
    解决方式:
    我终于找到新特性的bug啦,别急,有解决方案:

       @Test
        public void testMyErr() throws Exception {
            List<Person> peoples = new ArrayList<>(Arrays.asList(
                    new Person("思聪","杭州",19,50),
                    new Person("马云","北京",50,100),
                    new Person("思聪","北京",19,20),
                    new Person("温州大婶","西安",1,120),
                    new Person("温州大婶","杭州",1,100),
                    new Person("我",null,18,0),
                    new Person("温州大婶","新西兰",1,200)
            ));
    
            //+++++ 坑点+++++
    //        Stream<Person> stream = peoples.stream();
    //        List<String> collect = stream.map(Person::getName).collect(toList()); // 第一次使用 stream
    //        List<Person> collect1 = stream.filter(person -> person.getAge() > 18).collect(toList());// 第二次使用 stream
    //
            // 类似于一个stream的池子,用的时候取,每次都是个新的对象
            Supplier<Stream<Person>> streamSupplier = peoples::stream;
            List<String> collect3 = streamSupplier.get().map(Person::getName).collect(toList()); // 第一次使用 stream
            List<Person> collect4 =streamSupplier.get().filter(person -> person.getAge() > 18).collect(toList());// 第二次使用 stream
            System.out.println();
        }
    

    6.再补充
    前面由于仓促,有些不常用的用法没有提到,这里做出补充。

     // 过滤 filter
            List<Person> collect11 = streamSupplier.get().filter(person ->person.getAge() >= 22).collect(toList());
            System.out.println(collect11);
    
            // 选择字段过滤 map,这里可以在函数块中返回需要的数据
            List<String> collect1 = streamSupplier.get().map(Person::getName).collect(toList());
            List<String> collect11111 = streamSupplier.get().map(c->{
                System.out.println("1111");
                return c.getName() ;
            }).collect(toList());
    
            // 去重复,也比较常用,但是需要重写eques 和hashcode 的方法
            List<Person> collect2 = streamSupplier.get().distinct().collect(toList());
    
            // 限制条数,做分页可以使用
            List<Person> collect3 = streamSupplier.get().limit(4).collect(toList());
    
            // 统计数量
            long count = stream.filter(p -> p.getAge() > 20).count();
    
            // 扁平化
            List<String[]> collect4 = Arrays.stream(strs).map(s -> s.split("")).distinct().collect(toList());
            List<String[]> collect5 = Arrays.stream(strs).map(s -> s.split("a")).distinct().collect(toList());
    
            // 终端操作
    
            // 规约
    
            Optional<Integer> reduce = streamSupplier.get().filter(s -> s.getAge() < 30).map(Person::getAge).reduce(Integer::sum);
            Integer reduce1 = streamSupplier.get().filter(s -> s.getAge() < 40).map(Person::getAge).reduce(0,(a,b)->a+b);
            Integer reduce2 = streamSupplier.get().filter(s -> s.getAge() < 40).map(Person::getAge).reduce(0,(a,b)->a+b);
            Integer reduce3 = streamSupplier.get().filter(s -> s.getAge() < 40).map(Person::getAge).reduce(2,(a,b)->a+b);
    

    输出结果:

    简单过滤结果
    [{"age":22,"name":"name2"},{"age":33,"name":"name3"},{"age":44,"name":"name4"},{"age":55,"name":"name5"},{"age":66,"name":"name6"},{"age":77,"name":"name7"},{"age":77,"name":"name7"},{"age":88,"name":"name2"}]
    选择字段过滤结果
    ["name1","name2","name3","name4","name5","name6","name7","name7","name2"]
    ["name1","name2","name3","name4","name5","name6","name7","name7","name2"]
    去重复结果
    条数限制结果
    [{"age":11,"name":"name1"},{"age":22,"name":"name2"},{"age":33,"name":"name3"},{"age":44,"name":"name4"},{"age":55,"name":"name5"},{"age":66,"name":"name6"},{"age":77,"name":"name7"},{"age":88,"name":"name2"}]
    
    [{"age":11,"name":"name1"},{"age":22,"name":"name2"},{"age":33,"name":"name3"},{"age":44,"name":"name4"}]统计结果
    8扁平化结果
    
    [["j","a","v","a","8"],["i","s"],["e","a","s","y"],["t","o"],["u","s","e"]]
    [["j","v","8"],["is"],["e","sy"],["to"],["use"]]
    规约结果
    66
    66
    68
    

    相关文章

      网友评论

          本文标题:Java8新特性系列--流处理

          本文链接:https://www.haomeiwen.com/subject/nodswftx.html