zoukankan      html  css  js  c++  java
  • Java8 Stream —— 更丝滑的集合操作方式

    一.概念

    Stream是一种可供流式操作的数据视图有些类似数据库中视图的概念它不改变源数据集合如果对其进行改变的操作它会返回一个新的数据集合。

    总的来讲它有三大特性:在之后我们会对照着详细说明

           1、stream不存储数据

           2、stream不改变源数据

           3、stream的延迟执行特性

    二.优点

           1、代码简洁,函数式编程写出的代码简洁且意图明确,使用stream接口让你从此告别for循环。

           2、多核友好,Java函数式编程使得编写并行程序从未如此简单,你需要的全部就是调用一下parallel()方法。

    三.Stream API常用方法

    Stream操作分类
    中间操作(Intermediate operations) 无状态(Stateless) unordered() filter() map() mapToInt() mapToLong() mapToDouble() flatMap() flatMapToInt() flatMapToLong() flatMapToDouble() peek()
    有状态(Stateful) distinct() sorted() sorted() limit() skip()
    结束操作(Terminal operations) 非短路操作 forEach() forEachOrdered() toArray() reduce() collect() max() min() count()
    短路操作(short-circuiting) anyMatch() allMatch() noneMatch() findFirst() findAny()

    Stream上的所有操作分为两类:中间操作和结束操作,中间操作只是一种标记,只有结束操作才会触发实际计算。

    中间操作又可以分为无状态的和有状态的:

          无状态中间操作是指元素的处理不受前面元素的影响,而有状态的中间操作必须等到所有元素处理之后才知道最终结果,比如排序是有状态操作,在读取所有元素之前并不能确定排序结果;

    结束操作又可以分为短路操作和非短路操作

          短路操作是指不用处理全部元素就可以返回结果,比如找到第一个满足条件的元素。之所以要进行如此精细的划分,是因为底层对每一种情况的处理方式不同。

    常用中间件

          filter:过滤流,过滤流中的元素,返回一个符合条件的Stream

          map:转换流,将一种类型的流转换为另外一种流。(mapToInt、mapToLong、mapToDouble 返回int、long、double基本类型对应的Stream)

     flatMap:简单的说,就是一个或多个流合并成一个新流。(flatMapToInt、flatMapToLong、flatMapToDouble 返回对应的IntStream、LongStream、DoubleStream流。)

     distinct:返回去重的Stream。

      sorted:返回一个排序的Stream。

        peek:主要用来查看流中元素的数据状态。

         limit:返回前n个元素数据组成的Stream。属于短路操作

         skip:返回第n个元素后面数据组成的Stream。 

    结束操作

      forEach: 循环操作Stream中数据。

      toArray: 返回流中元素对应的数组对象。

      reduce: 聚合操作,用来做统计。

      collect: 聚合操作,封装目标数据。

    min、max、count: 聚合操作,最小值,最大值,总数量。

       anyMatch: 短路操作,有一个符合条件返回true。

        allMatch: 所有数据都符合条件返回true。

    noneMatch: 所有数据都不符合条件返回true。

        findFirst: 短路操作,获取第一个元素。

         findAny: 短路操作,获取任一元素。

    forEachOrdered: 暗元素顺序执行循环操作。

    四.常用场景和方法举例

    1.迭代

    forEach()方法:void forEach(Consumer< ? super T> action);

    peek()方法:Stream peek(Consumer< ? super T> action);

    List<String> list=...
    // 传统for循环
    for (String s : list) {
        System.out.println(s);
    }
    
    // 使用forEach(结束操作),对集合的修改不会影响原集合
    list.stream().forEach(x -> {
        System.out.println(x);
    });
    
    // 使用peek(中间操作),对集合的修改也会体现在原集合中
    list = list.stream().peek(x -> {
        System.out.println(x);
    }).collect(Collectors.toList());

    2.转换

    map()方法:Stream map(Function< ? super T, ? extends R> mapper);

    public class Person {
        private Integer  id;
        private String name;
        private String sex;
        private Integer age;
        //提供get,set,和满参构造函数
    }
    
    public class TestMap {
      public static void main(String[] args) {
        List<Person> persionList = new ArrayList<Person>();
        persionList.add(new Person(1,"张三","男",38));
        persionList.add(new Person(2,"小小","女",2));
        persionList.add(new Person(3,"李四","男",65));
        persionList.add(new Person(4,"王五","女",20));
        persionList.add(new Person(5,"赵六","男",38));
        persionList.add(new Person(6,"大大","男",65));
    
        //1、只取出该集合中所有姓名组成一个新集合
        List<String> nameList=persionList.stream().map(Person::getName).collect(Collectors.toList()); //未去重
        List<String> nameList=persionList.stream().map(Person::getName).distinct().collect(Collectors.toList()); //去重
        System.out.println(nameList.toString());
    
        //2、只取出该集合中所有id组成一个新集合
        List<Integer> idList=persionList.stream().mapToInt(Person::getId).boxed().collect(Collectors.toList());
        System.out.println(idList.toString());
    
        //3、list转map,key值为id,value为Person对象
        Map<Integer, Person> personmap = persionList.stream().collect(Collectors.toMap(Person::getId, person -> person));
        System.out.println(personmap.toString());
    
        //4、list转map,key值为id,value为name
        Map<Integer, String> namemap = persionList.stream().collect(Collectors.toMap(Person::getId, Person::getName));
        System.out.println(namemap.toString());
    
        //5、进行map集合存放,key为age值 value为Person对象 它会把相同age的对象放到一个集合中
        Map<Integer, List<Person>> ageMap = persionList.stream().collect(Collectors.groupingBy(Person::getAge));
        System.out.println(ageMap.toString());
    
        //6、获取最小年龄
        Integer ageMin = persionList.stream().mapToInt(Person::getAge).min().getAsInt();
        System.out.println("最小年龄为: "+ageMin);
    
        //7、获取最大年龄
        Integer ageMax = persionList.stream().mapToInt(Person::getAge).max().getAsInt();
        System.out.println("最大年龄为: "+ageMax);
    
        //8、集合年龄属性求和
        Integer ageAmount = persionList.stream().mapToInt(Person::getAge).sum();
        System.out.println("年龄总和为: "+ageAmount);
      }
    }

    3.过滤

    filter()方法:Stream filter(Predicate< ? super T> predicate);

    public class TestFilter {
      public static void main(String[] args) {
        List<Person> persionList = new ArrayList<Person>();
        persionList.add(new Person(1, "张三", "男", 8));
        persionList.add(new Person(2, "小小", "女", 2));
        persionList.add(new Person(3, "李四", "男", 25));
        persionList.add(new Person(4, "王五", "女", 8));
        persionList.add(new Person(5, "赵六", "女", 25));
        persionList.add(new Person(6, "大大", "男", 65));
    
        //1、查找年龄大于20岁的人数
        long  age=persionList.stream().filter(p->p.getAge()>20).count();
        System.out.println(age);
    
        //2、查找年龄大于20岁,性别为男的人数
        List<Person>  ageList=persionList.stream().filter(p->p.getAge()>20).filter(p->"男".equals(p.getSex())).collect(Collectors.toList());
        System.out.println(ageList.size());
    
           //3、查找年龄大于20岁的男性 或 年龄大于18岁的女性人数
           List<Person>  ageList=persionList.stream().filter(p -> (p.getAge()>20 && "男".equals(p.getSex())) || (p.getAge()>18 && "女".equals(p.getSex()))).collect(Collectors.toList());
           System.out.println(ageList.size());
    
        //4、过滤掉 姓名、性别、年龄 均相同的重复项
        List<Person>  ageList=persionList.stream().collect(Collectors.collectingAndThen(Collectors.toCollection(() -> new TreeSet<>(Comparator.comparing(p -> p.getName() + ";" + p.getSex() + ";" + p.getAge()))), ArrayList::new));
        System.out.printIn(ageList.size());
      }
    }

    4.排序

    sorted() 排序方法:

    public class Test {
        public static void main(String[] args) {
            List<Person> persionList = new ArrayList<Person>();
            persionList.add(new Person(1, "张三", "男", 8));
            persionList.add(new Person(2, "小小", "女", 2));
            persionList.add(new Person(3, "李四", "男", 25));
            persionList.add(new Person(4, "王五", "女", 8));
            persionList.add(new Person(5, "赵六", "女", 25));
            persionList.add(new Person(6, "大大", "男", 65));
     
            //根据年龄升序
            persionList = persionList.stream().sorted(Comparator.comparing(Person::getAge)).collect(Collectors.toList());
            persionList = persionList.stream().sorted(Comparator.comparingInt(x -> x.getAge())).collect(Collectors.toList());
            persionList = persionList.stream().sorted((a, b) -> a.getAge().compareTo(b.getAge())).collect(Collectors.toList());
            //根据年龄降序
            persionList = persionList.stream().sorted(Comparator.comparing(Person::getAge).reversed()).collect(Collectors.toList());
            persionList = persionList.stream().sorted((a, b) -> b.getAge().compareTo(a.getAge())).collect(Collectors.toList());
            //根据年龄降序,年龄相同的再根据id升序
            persionList = persionList.stream().sorted(Comparator.comparing(Person::getAge).reversed().thenComparing(Person::getId)).collect(Collectors.toList());
        }
    }

  • 相关阅读:
    常用操作之增、删、改、查
    文本编辑器相关操作
    关于Secondary NameNode
    hive基础概念总结(1)
    Shell 十三问[转]
    《SQL Server 2012 Tutorials Analysis Services Multidimensional Modeling》读后感
    HDFS随笔(1)
    Hue for Apache Hadoop
    大数据面试题总结
    关于数据倾斜
  • 原文地址:https://www.cnblogs.com/superSubfn/p/12029634.html
Copyright © 2011-2022 走看看