• 关于java8新特性 Stream流的常规用法总结


    一、stream 的种类

    • stream有两种流

    一种是串行流–Collection.Stream() --常用的
    另一个是并行流–Collection.parallelStream()
    所有Collection集合的实现类都继承了这两个方法
    两者的使用场景是:

    1. 单核 cpu 环境,不推荐使用 parallel stream,在多核 cpu 且有大数据量的条件下,推荐使用 paralle stream;
    2. 并行流parallel stream 底层使用的是 JVM 的 ForkJoinPool,在cpu恰好将线程分配到多个核心的条件下,可以达到一个很高的运行效率;
    3. Parallel Stream 受引 CPU 环境影响很大,当没分配到多个cpu核心时,加上引用 forkJoinPool 的开销,运行效率可能还不如普通的 Stream;

    二、 stream 流的多种获取方式

    1)从 Collection 和 数组中获取
    Collection.stream()
    Collection.parallelStream()
    Arrays.stream(T array)
    Stream.of()

     //(1)Stream.of方法
    Stream stream = Stream.of("hello", "xxx", "yyy", "beijing", "shanghai");
    
    //(2)Arrays.stream方法
    IntStream stream = Arrays.stream(new int[]{100, 200, 300, 400});
    
    //(3)iterate迭代 --从0开始,循环10个数,每个数+2打印出来,打印的是0,2,4....18
    Stream iterate = Stream.iterate(0, x -> x + 2);
    iterate.limit(10).forEach(System.out::println);
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    2)从BufferedReader中获取
    java.io.BufferedReader.lines()

    3)静态工厂
    java.util.stream.IntStream.range()
    java.nio.file.Files.walk()

    4)自己构建
    java.util.Spliterator

    5)其它
    Random.ints()
    BitSet.stream()
    Pattern.splitAsStream(java.lang.CharSequence)
    JarFile.stream()

    三、流的操作类型简介

    【—中间操作—】

    一个流可以后面跟随零个或多个 intermediate 操作。其目的主要是打开流,做出某种程度的数据映射/过滤,然后返回一个新的流,交给下一个操作使用。这类操作都是惰性化的(lazy),就是说,仅仅调用到这类方法,并没有真正开始流的遍历,这被称为“惰性求值”。

    操作操作说明
    map (mapToInt, flatMap 等)转换或映射。将数据从一种格式转换成另一种格式。
    peekl与map用法类似,但是map会改变元素本身,peek不改变元素本身(对象的话会改变)
    filter过滤,从流中排除元素
    distinct筛选,通过流所生成元素的 equals() 去除重复元素
    sorted排序
    limit限制返回个数
    skip删除集合对象前n个元素,跳过元素
    unordered不关心集合的顺序,例如Stream.distinct就是可以从中获益

    —终端操作—

    通常分为最终的消费:比如foreach 之类的归纳:collect等 两大类
    forEach、forEachOrdered、toArray、reduce、collect、min、max、count、anyMatch、allMatch、noneMatch、findFirst、findAny、iterator。

    需要注意的是,对于基本数值型,目前有三种对应的包装类型 Stream
    IntStream、LongStream、DoubleStream。当然我们也可以用 Stream、Stream >、Stream,但是 boxing 和 unboxing 会很耗时,所以特别为这三种基本数值型提供了对应的 Stream。

    1)中间操作示例

            List<User> userList = new ArrayList<>();
            User A = new User ();
            A.setName("zhangsan");
            A.setSex("boy");
            A.setMobilephone("111");
            User B = new User ();
            B.setName("lisi");
            B.setSex("girl");
            A.setMobilephone("222");
            User C = new User ();
            C.setName("aoteman");
            C.setSex("girl");
            C.setMobilephone("333");
            userList.add(A);
            userList.add(B);
            userList.add(C);
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16

    1.1 map 转换

    • map里面的方法必须是有返回值的,比如get方法
    • new User()方法等,set方法这种返回void的不能在map中使用,否则会报错!
    //获取名字集合
    List<String> names= resultItems.stream().map(User::getName).collect(Collectors.toList());
    
    //依次打印名字
    userList.stream().map(e->e.getName()).forEach(System.out::println);
    
    //名字全部大写
    userList.stream().map(e->e.getName().toUpperCase()).forEach(System.out::println);
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • mapToInt
    //IntStream求和
    int sum = userList.stream().mapToInt(user -> Integer.valueOf(user.getMobilephone())).sum();
    
    • 1
    • 2
    • flatMap 流的扁平化
      map只是一维一对一的映射
      但是flatMap可以把二维的集合映射成一维的
    //["Hello","World"]  输出 HeloWrd
    String[] words = new String[]{"Hello","World"};
    List<String> collect = Arrays.stream(words).map(word -> word.split(""))
    .flatMap(Arrays::stream).distinct().collect(toList());
    
     collect.forEach(System.out::print);
     //输出HeloWrd
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    1.2 peek

    peek 操作接收的是一个 Consumer< T > 函数。peek 操作会按照 Consumer< T > 函数提供的逻辑去消费流中的每一个元素,同时有可能改变元素内部的一些属性

    Consumer< T > :消费就是 “用掉” ,返回的是 void

    • peek接收一个Consumer,而map接收一个Function
    • Consumer是没有返回值的,它只是对Stream中的元素进行某些操作,但是操作之后的数据并不返回到Stream中,所以Stream中的元素还是原来的元素。peek-String不会发生变化 , 而peek-Object会发生变化
    • 而Function是有返回值的,这意味着对于Stream的元素的所有操作都会作为新的结果返回到Stream中。
    //peek-String不会变化,输出的依然是小写
    Stream.of("one", "two").peek(u -> u.toUpperCase()) .forEach(System.out::println);
    输出:
    one
    two
    
    //map 输出的都是大写
    Stream.of("one", "two").map(u -> u.toUpperCase()) .forEach(System.out::println);
    输出:
    ONE
    TWO
    
    //peek-Object会发生变化  设置性别都是boy
    List<User> boy = userList.stream().peek(user -> user.setSex("boy")).collect(Collectors.toList());
    boy.stream().map(User::getSex).forEach(System.out::println);
    输出:
    boy
    boy
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18

    1.3 filter 筛选

    //筛选女生的姓名集合并打印
    userList.stream().filter(u -> "girl".equals(u.getSex())).map(user -> user.getName()).forEach(System.out::println);
    
    • 1
    • 2

    1.4 distinct 去除集合中的重复元素

    如果集合中是对象,那么对象要重写equals()方法方可达到去重效果
    集合中是基本数据类型,直接去重即可

            //第一个map和第三个mao重复,去重处理
            ArrayList<HashMap<String,String>> mapList = new ArrayList<>();
            HashMap<String,String> map1 = new HashMap<>();
            map1.put("name","paidaxing");
            map1.put("age","18");
            mapList.add(map1);
    
            HashMap<String,String> map2 = new HashMap<>();
            map2.put("name","haimianbobo");
            map2.put("age","16");
            mapList.add(map2);
    
            HashMap<String,String> map3 = new HashMap<>();
            map3.put("name","paidaxing");
            map3.put("age","18");
            mapList.add(map3);
    
            mapList.stream().distinct().forEach(System.out::println);
            
            输出:
            {name=paidaxing, age=18}
            {name=haimianbobo, age=16}
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22

    1.5 sorted 排序

    使用stored()方法排序有两种方法:

    1. stored():默认使用自然序排序, 其中的元素必须实现Comparable接口,适用基本数据类型
    2. sorted(Comparator comparator) :我们可以使用lambada 来创建一个Comparator实例。
      实现方法有两种:
      1)JavaBean(数据)实现Compareable
      2)使用sorted()方法时通过Lambda表达式传入自定义比较器
    //------------------------------自然排序---------------------------------------------------
    Stream.of("bbb","ddd","aaa","ccc").sorted().forEach(System.out::println);
    输出:
    aaa
    bbb
    ccc
    ddd
    //--------------------------------简单Lambda表达式------------------------------------
    ArrayList<HashMap<String,String>> mapList = new ArrayList<>();
    HashMap<String,String> map1 = new HashMap<>();
    map1.put("name","paidaxing");
    map1.put("age","18");
    mapList.add(map1);
    HashMap<String,String> map2 = new HashMap<>();
    map2.put("name","haimianbobo");
    map2.put("age","16");
    mapList.add(map2);
    HashMap<String,String> map3 = new HashMap<>();
    map3.put("name","paidaxing1");
    map3.put("age","21");
    mapList.add(map3);
    //按照年纪升序排序,自然排序        
    mapList.stream().sorted((mapOne,mapTwo) -> Integer.compare(Integer.valueOf(mapOne.get("age")),Integer.valueOf(mapTwo.get("age")))).forEach(System.out::println);
    输出:
    {name=haimianbobo, age=16}
    {name=paidaxing, age=18}
    {name=paidaxing1, age=21}
    
    //按照年纪降序排序
    mapList.stream().sorted((mapTwo,mapOne) -> Integer.compare(Integer.valueOf(mapOne.get("age")),Integer.valueOf(mapTwo.get("age")))).forEach(System.out::println);
    
    //---------------------------------Lambda表达式传入自定义比较器----------------------------------
    userList.stream().sorted((o1,o2)->{
                        int n1=o1.getAge()-o2.getAge();
                        int n2=Double.compare(o1.getSalary(), o2.getSalary());
                        return n1==0?n2:n1; }).forEach(System.out::println);
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36

    1.6 limit 限制使其元素不超过给定数量

            ArrayList<HashMap<String,String>> mapList = new ArrayList<>();
            HashMap<String,String> map1 = new HashMap<>();
            map1.put("name","paidaxing");
            map1.put("age","18");
            mapList.add(map1);
    
            HashMap<String,String> map2 = new HashMap<>();
            map2.put("name","haimianbobo");
            map2.put("age","16");
            mapList.add(map2);
    
            HashMap<String,String> map3 = new HashMap<>();
            map3.put("name","paidaxing1");
            map3.put("age","21");
            mapList.add(map3);
    
            mapList.stream().limit(2).forEach(System.out::println);
            输出:
            {name=paidaxing, age=18}
            {name=haimianbobo, age=16}
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20

    1.7 skip 删除集合前n个参数,若流中元素不足 n 个,则返回一个空流

    mapList.stream().skip(2).forEach(System.out::println);
    输出:
    {name=paidaxing1, age=21}
    
    • 1
    • 2
    • 3

    2)终端操作示例

    2.1 anyMatch/allMatch/noneMatch(匹配)

    返回值均为boolean类型

    allMatch():检查是否匹配所有元素
    anyMatch():检查是否至少匹配一个元素
    noneMatch():检查是否没有匹配的元素

    //是否其中有女生
    boolean b = userList.stream().anyMatch(user -> “girl”.equals(user.getSex()));
    System.out.println(b);
    输出:true

    //是否全部都是女生
    boolean b = userList.stream().allMatch(user -> “girl”.equals(user.getSex()));
    System.out.println(b);
    输出:false

    //是不是没有女生
    boolean b = userList.stream().noneMatch(user -> “girl”.equals(user.getSex()));
    System.out.println(b);
    输出:false

    2.2 findFirst/findAny 返回流中的一个元素,返回类型均为Optional类型的

    Optional类:Java 8 中为了解决空指针异常而引入的类。

    findFirst():返回第一个元素
    findAny():返回当前流中的任意元素,findAny() 方法在串行和并行流中返回任意一个数据时,总是返回最快得到的那个元素。

    取第一个用户的名称
    Optional first = userList.stream().findFirst();
    User user = first.get();
    System.out.println(user.getName());

    2.3 min/max (最值) 参数为Comparator类型

    //设置值
    ArrayList> mapList = new ArrayList<>();
    HashMap map1 = new HashMap<>();
    map1.put(“name”,“paidaxing”);
    map1.put(“age”,“18”);
    mapList.add(map1);
    HashMap map2 = new HashMap<>();
    map2.put(“name”,“haimianbobo”);
    map2.put(“age”,“16”);
    mapList.add(map2);
    HashMap map3 = new HashMap<>();
    map3.put(“name”,“paidaxing1”);
    map3.put(“age”,“21”);
    mapList.add(map3);

    //查询最大年纪的
    Optional> max1 = mapList.stream().max((mapOne, mapTwo) -> Integer.compare(Integer.valueOf(mapOne.get(“age”)), Integer.valueOf(mapTwo.get(“age”))));
    System.out.println(max1.get());

    2.4 reduce (规约/聚合)

    reduce 作用是把 Stream 元素组合起来。它提供一个起始值,然后依照运算规则(BinaryOperator),和前面 Stream 的第一个、第二个、第 n 个元素组合。从这个意义上说,字符串拼接、数值的 sum、min、max、average 都是特殊的 reduce

    //字符串拼接
    String reduce = userList.stream().map(u -> u.getName()).reduce("name: ", (x, y) -> x + y);
    System.out.println(reduce);
    输出:
    name: zhangsanlisiaoteman

    //数值求和 10+20+30+40 = 100
    List list= Arrays.asList(20,30,40);
    Integer sum = list.stream().reduce(10, (x, y) -> x + y);
    System.out.println(sum);

    //数值求和 10+20+30+40 = 100
    List list= Arrays.asList(20,30,40);
    Integer sum = list.stream().reduce(10, Integer::sum);
    System.out.println(sum);

    2.5 Collect (把数据按照指定的集合类型进行返回)

    • 名称大写并转成list 【Collectors.toList()】

    List collect = userList.stream().peek(u -> u.setName(u.getName().toUpperCase())).collect(Collectors.toList());
    collect.stream().map(User::getName).forEach(System.out::println);
    输出:
    ZHANGSAN
    LISI
    AOTEMAN

    • 名称用逗号拼接 【 Collectors.joining(“,”)】

    String collect = userList.stream().map(User::getName).collect(Collectors.joining(“,”));
    System.out.println(collect);
    输出:
    zhangsan,lisi,aoteman

    • List转为Map 【Collectors.toMap() 】

    1、指定key-value,value是对象中的某个属性值。
    Map userMap1 = userList.stream().collect(Collectors.toMap(User::getId,User::getName));
    2.1、指定key-value,value是对象本身,User->User 是一个返回本身的lambda表达式
    Map userMap2 = userList.stream().collect(Collectors.toMap(User::getId,User->User));
    2.2、指定key-value,value是对象本身,Function.identity()是简洁写法,也是返回对象本身
    Map userMap3 = userList.stream().collect(Collectors.toMap(User::getId, Function.identity()));
    3、指定key-value,value是对象本身,key 冲突的解决办法,这里选择第二个key覆盖第一个key。
    Map userMap4 = userList.stream().collect(Collectors.toMap(User::getId, Function.identity(),(key1,key2)->key2));

    • 按照指定的属性分组 【Collectors.groupingBy()】

    返回一个Map,键为分组条件;
    值为一个单列集合Collection,表示满足分组条件的元素
    //按照性别分组
    Map collect = userList.stream().collect(Collectors.groupingBy(user -> user.getSex()));
    collect.keySet().stream().forEach(System.out::println);
    输出:
    girl =[User{name=‘lisi’, sex=‘girl’}, User{name=‘aoteman’, sex=‘girl’}]
    boy =[User{name=‘zhangsan’, sex=‘boy’}]

    • 按照指定的条件分区 【Collectors.partitioningBy()】

    Map collect = userList.stream().collect(Collectors.partitioningBy(user -> user.getSex().equals(“girl”)));
    collect.keySet().stream().forEach(System.out::println);
    输出:
    true=[User{name=‘lisi’, sex=‘girl’}, User{name=‘aoteman’, sex=‘girl’}]
    false =[User{name=‘zhangsan’, sex=‘boy’}]

    Stream stream = Stream.of(“John”, “Baby”, “Lisa”, “张三”, “李四”);
    final Map map = stream.collect(Collectors.partitioningBy(s -> {
    int code = s.codePointAt(0);
    // 如果是英文字母,划分到true分组
    return (code >= 65 && code <= 90) || (code >= 97 && code <= 122);
    }));
    // 输出分组结果
    map.forEach((isEnglishName, names) -> {
    if (isEnglishName) {
    System.out.println(“英文名称:”);
    } else {
    System.out.println(“中文名称:”);
    }
    names.forEach(name -> System.out.println(“\t” + name));
    });
    输出:
    中文名称:
    张三
    李四
    英文名称:
    John
    Baby
    Lisa

    ———————————————————————————
    参考文章链接:
    https://blog.csdn.net/Vaingloryss/article/details/99704860
    https://blog.csdn.net/vx539413949/article/details/124180037

  • 相关阅读:
    微服务系统设计——接口文档管理设计
    【航天物流组参赛ReadMe.md】
    【SQL】MySQL中的存储引擎、事务、锁、日志
    【权限管理项目总结】SpringBoot+MyBatis+Shiro+EhCache+Thymeleaf:编码+功能测试+知识点
    第八章 字符输入输出和输入验证
    使用vue-cli搭建SPA项目
    mongodb_exporter +prometheus
    【基于英语记单词的微信小程序的开发与设计-哔哩哔哩】 https://b23.tv/aBd4NHg
    英雄联盟比赛选手的六芒星能力图动画是如何制作的?
    javaIO流07:处理流BufferedReader和BufferedWriter,Buffer拷贝
  • 原文地址:https://blog.csdn.net/MyfishCake/article/details/125180594