• Java8 stream处理List,Map总结


    Java 8 Stream

    Java 8 API添加了一个新的抽象称为流Stream,可以让你以一种声明的方式处理数据。

    Stream 使用一种类似用 SQL 语句从数据库查询数据的直观方式来提供一种对 Java 集合运算和表达的高阶抽象。

    Stream API可以极大提高Java程序员的生产力,让程序员写出高效率、干净、简洁的代码。

    这种风格将要处理的元素集合看作一种流, 流在管道中传输, 并且可以在管道的节点上进行处理, 比如筛选, 排序,聚合等。

    元素流在管道中经过中间操作(intermediate operation)的处理,最后由最终操作(terminal operation)得到前面处理的结果。

    什么是 Stream?

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

    • <strong元素队列< strong="">元素是特定类型的对象,形成一个队列。 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() − 为集合创建并行流

     下面写一下,我们经常会用到的一些操作案例

    一,排序

       List     
    
          1, 对象集合排序
            //降序,根据创建时间降序;
            List<User> descList = attributeList.stream().sorted(Comparator.comparing(User::getCreateTime, Comparator.nullsLast(Date::compareTo)).reversed())
                      .collect(Collectors.toList());
            //升序,根据创建时间升序;
            List<User> ascList = attributeList.stream().sorted(Comparator.comparing(User::getCreateTime, Comparator.nullsLast(Date::compareTo)))
                      .collect(Collectors.toList());
    
            2, 数字排序
            List<Integer> numbers = Arrays.asList(3, 2, 2, 3, 7, 3, 5);
    
            //升序
            List<Integer> ascList = numbers.stream().sorted().collect(Collectors.toList());
            结果: [2, 2, 3, 3, 3, 5, 7]
    
            //倒序
            List<Integer> descList = numbers.stream().sorted((x, y) -> y - x).collect(Collectors.toList());
            结果:[7, 5, 3, 3, 3, 2, 2]
    
           3, 字符串排序
         List<String> strList = Arrays.asList("a", "ba", "bb", "abc", "cbb", "bba", "cab");
    
            //自然排序
            List<String> ascList = strList.stream().sorted().collect(Collectors.toList());
            结果:[a, abc, ba, bb, bba, cab, cbb]
    
            //反转,倒序
            ascList.sort(Collections.reverseOrder());
            结果:[cbb, cab, bba, bb, ba, abc, a]
    
            //直接反转集合
            Collections.reverse(strList);
            结果:[cab, bba, cbb, abc, bb, ba, a]
      
       Map
         //HashMap是无序的,当我们希望有顺序地去存储key-value时,就需要使用LinkedHashMap了,排序后可以再转成HashMap。
            //LinkedHashMap是继承于HashMap,是基于HashMap和双向链表来实现的。
            //LinkedHashMap是线程不安全的。
            Map<String,String> map = new HashMap<>();
            map.put("a","123");
            map.put("b","456");
            map.put("z","789");
            map.put("c","234");
    
            //map根据value正序排序
            LinkedHashMap<String, String> linkedMap1 = new LinkedHashMap<>();
            map.entrySet().stream().sorted(Comparator.comparing(e -> e.getValue())).forEach(x -> linkedMap1.put(x.getKey(), x.getValue()));
            结果:{a=123, c=234, b=456, z=789}
    
            //map根据value倒序排序
            LinkedHashMap<String, String> linkedMap2 = new LinkedHashMap<>();
            map.entrySet().stream().sorted(Collections.reverseOrder(Map.Entry.comparingByValue())).forEach(x -> linkedMap2.put(x.getKey(), x.getValue()));
            结果:{z=789, b=456, c=234, a=123}
    
            //map根据key正序排序
            LinkedHashMap<String, String> linkedMap3 = new LinkedHashMap<>();
            map.entrySet().stream().sorted(Comparator.comparing(e -> e.getKey())).forEach(x -> linkedMap3.put(x.getKey(), x.getValue()));
            结果:{a=123, b=456, c=234, z=789}
    
            //map根据key倒序排序
            LinkedHashMap<String, String> linkedMap4 = new LinkedHashMap<>();
            map.entrySet().stream().sorted(Collections.reverseOrder(Map.Entry.comparingByKey())).forEach(x -> linkedMap4.put(x.getKey(), x.getValue()));
            结果:{z=789, c=234, b=456, a=123}

    二,List 转 Map

         1、指定key-value,value是对象中的某个属性值。
            Map<Integer,String> userMap1 = userList.stream().collect(Collectors.toMap(User::getId,User::getName));
    
            2、指定key-value,value是对象本身,User->User 是一个返回本身的lambda表达式
            Map<Integer,User> userMap2 = userList.stream().collect(Collectors.toMap(User::getId,User->User));
    
            3、指定key-value,value是对象本身,Function.identity()是简洁写法,也是返回对象本身
            Map<Integer,User> userMap3 = userList.stream().collect(Collectors.toMap(User::getId, Function.identity()));
    
            4、指定key-value,value是对象本身,Function.identity()是简洁写法,也是返回对象本身,key 冲突的解决办法,这里选择第二个key覆盖第一个key。
            Map<Integer,User> userMap4 = userList.stream().collect(Collectors.toMap(User::getId, Function.identity(),(key1,key2)->key2));
    
            5、将List根据某个属性进行分组,放入Map;然后组装成key-value格式的数据,分组后集合的顺序会被改变,所以事先设置下排序,然后再排序,保证数据顺序不变。
            List<GoodsInfoOut> lst = goodsInfoMapper.getGoodsList();
            Map<String, List<GoodsInfoOut>> groupMap = lst.stream().collect(Collectors.groupingBy(GoodsInfoOut::getClassificationOperationId));
            List<HomeGoodsInfoOut> retList = groupMap.keySet().stream().map(key -> {
                HomeGoodsInfoOut mallOut = new HomeGoodsInfoOut();
                mallOut.setClassificationOperationId(key);
                if(groupMap.get(key)!=null && groupMap.get(key).size()>0) {
                    mallOut.setClassificationName(groupMap.get(key).get(0).getClassificationName());
                    mallOut.setClassificationPic(groupMap.get(key).get(0).getClassificationPic());
                    mallOut.setClassificationSort(groupMap.get(key).get(0).getClassificationSort());
                }
                mallOut.setGoodsInfoList(groupMap.get(key));
                return mallOut;
            }).collect(Collectors.toList());
            List<HomeGoodsInfoOut> homeGoodsInfoOutList = retList.stream().sorted(Comparator.comparing(HomeGoodsInfoOut::getClassificationSort))
                                     .collect(Collectors.toList());

           5、根据用户性别将数据 - 分组
        
    Map<String, List<UserInfo>> groupMap = userList.stream().collect(Collectors.groupingBy(UserInfo::getSex()));

           6、List实体转Map,想要有序的话,就使用以下操作(TreeMap 有序;Map 无序)
        
    TreeMap<String, List<BillPollEntity>> monthBillPollMap = s.stream().collect(Collectors.groupingBy(t -> t.getDrawTime()), TreeMap::new, Collectors.toList()));
         Map<String, List<BillPollEntity>> monthBillPollMap = s.stream().collect(Collectors.groupingBy(BillPollEntity::getDrawTime));
     


    三,Map 转 List

         Map<String,String> map1 = new HashMap<>();
            map1.put("a","123");
            map1.put("b","456");
            map1.put("z","789");
            map1.put("c","234");
    
            1、默认顺序
            List<UserInfo> list0 = map1.entrySet().stream()
                       .map(e -> new UserInfo(e.getValue(), e.getKey()))
                       .collect(Collectors.toList()); 结果:[UserInfo(userName=123, mobile=a), UserInfo(userName=456, mobile=b), UserInfo(userName=234, mobile=c), UserInfo(userName=789, mobile=z)]
    2、根据Key排序 List<UserInfo> list1 = map1.entrySet().stream()
                       .sorted(Comparator.comparing(e -> e.getKey())).map(e -> new UserInfo(e.getKey(), e.getValue()))
                       .collect(Collectors.toList()); 结果:[UserInfo(userName=a, mobile=123), UserInfo(userName=b, mobile=456), UserInfo(userName=c, mobile=234), UserInfo(userName=z, mobile=789)]
    3、根据Value排序 List<UserInfo> list2 = map1.entrySet().stream()
                      .sorted(Comparator.comparing(Map.Entry::getValue))
                      .map(e -> new UserInfo(e.getKey(), e.getValue()))
                      .collect(Collectors.toList()); 结果:[UserInfo(userName=a, mobile=123), UserInfo(userName=c, mobile=234), UserInfo(userName=b, mobile=456), UserInfo(userName=z, mobile=789)]
    3、根据Key排序 List<UserInfo> list3 = map1.entrySet().stream()
                      .sorted(Map.Entry.comparingByKey())
                      .map(e -> new UserInfo(e.getKey(), e.getValue()))
                      .collect(Collectors.toList()); 结果:[UserInfo(userName=a, mobile=123), UserInfo(userName=b, mobile=456), UserInfo(userName=c, mobile=234), UserInfo(userName=z, mobile=789)]

    四,从List中获取某个属性

    //拿出所有手机号
    List<String> mobileList = userList.stream().map(RemindUserOut::getMobile).collect(Collectors.toList());

    //拿出所有AppId,并去重

    List<String> appIdList = appIdList.stream().map(WechatWebViewDomain::getAppId).collect(Collectors.toList()).stream().distinct().collect(Collectors.toList());

    //拿出集合中重复的billNo,【.filter(map->StringUtils.isNotEmpty(map.getBillNo()))】这是过滤掉为空的数据;否则,有空数据会抛异常

    List<String> repeatCodeList = resultList.stream().filter(map->StringUtils.isNotEmpty(map.getBillNo())).collect(Collectors.groupingBy(BillUploadIn::getBillNo, Collectors.counting())).entrySet().stream().filter(entry -> entry.getValue() > 1).map(Map.Entry::getKey).collect(Collectors.toList());

    //拿出集合中几个属性拼接后的字符串
    List<String> strList = myList.stream().map(p -> p.getName() + "-" + p.getMobile()).collect(Collectors.toList());

    五,筛选并根据属性去重

    List<UserInfo> uList = new ArrayList<>();
    UserInfo u1 = new UserInfo(1,"小白","15600000000");
    UserInfo u2 = new UserInfo(2,"小黑","15500000000");
    uList.add(u1);
    uList.add(u2);
    
    //过滤名字是小白的数据
    List list1= uList.stream()
    .filter(b -> "小白".equals(b.getUserName()))
    .collect(Collectors.collectingAndThen(Collectors.toCollection(() -> new TreeSet<>(Comparator.comparing(b -> b.getId()))), ArrayList::new));
    结果:list1===[UserInfo(id=1, userName=小白, mobile=15600000000)]
    //根据ID去重 List list2= uList.stream() .collect(Collectors.collectingAndThen(Collectors.toCollection(() -> new TreeSet<>(Comparator.comparing(b -> b.getId()))), ArrayList::new));
    结果:list2===[UserInfo(id=1, userName=小白, mobile=15600000000), UserInfo(id=2, userName=小黑, mobile=15500000000)]

      //整个数据去重
      list = list.stream().distinct().collect(Collectors.toList());

    
    

    六,计算;和,最大,最小,平均值。

    List<UserInfo> uList = new ArrayList<>();
    UserInfo user1 = new UserInfo(1,"小白","15600000000",10,new BigDecimal(10));
    UserInfo user2 = new UserInfo(2,"小黑","15500000000",15,new BigDecimal(20));
    UserInfo user3 = new UserInfo(2,"小彩","15500000000",88,new BigDecimal(99));
    uList.add(user1);
    uList.add(user2);
    uList.add(user3);
    
    //
    Double d1 = uList.stream().mapToDouble(UserInfo::getNum).sum();
    结果:113.0
    //最大
    Double d2 = uList.stream().mapToDouble(UserInfo::getNum).max().getAsDouble();
    结果:88.0
    //最小
    Double d3 = uList.stream().mapToDouble(UserInfo::getNum).min().getAsDouble();
    结果:10.0
    //平均值
    Double d4 = uList.stream().mapToDouble(UserInfo::getNum).average().getAsDouble();
    结果:37.666666666666664
    
    //除了统计double类型,还有int和long,bigDecimal需要用到reduce求和
    DecimalFormat df = new DecimalFormat("0.00");//保留两位小数点
    //和;可过滤掉NULL值
    BigDecimal add = uList.stream().map(UserInfo::getPrice).reduce(BigDecimal.ZERO, BigDecimal::add);
    BigDecimal add = uList.stream().filter(s->t.getPrice()!=null).map(UserInfo::getPrice).reduce(BigDecimal.ZERO, BigDecimal::add)
    System.out.println(df.format(add));
    结果:129.00 //最大 Optional<UserInfo> max = uList.stream().max((u1, u2) -> u1.getNum().compareTo(u2.getNum())); System.out.println(df.format(max.get().getPrice()));
    结果:99.00 //最小 Optional<UserInfo> min = uList.stream().min((u1, u2) -> u1.getNum().compareTo(u2.getNum())); System.out.println(df.format(min.get().getPrice()));
    结果:10.00

    //求和,还有mapToInt、mapToLong、flatMapToDouble、flatMapToInt、flatMapToLong
    list.stream().mapToDouble(UserInfo::getNum).sum();
    //最大 list.stream().mapToDouble(UserInfo::getNum).max();
    //最小 list.stream().mapToDouble(UserInfo::getNum).min();
    //平均值 list.stream().mapToDouble(UserInfo::getNum).average();

    未完,待续...

    list  [lɪst]  详细X
    基本翻译
    n. 列表,清单;(船)倾侧;围栏;赛场,战场;(织物的)镶边;<旧>渴望,喜好;(尤指按重要程度排列的)事物清单
    v. 列清单,拟订清单;把……列入名单;(使)(公司)上市;标价;(船)倾斜;<旧>征召(士兵);<旧>想要,喜好
    网络释义
    list:
    price list: 价目表
    packing list: 装箱单

  • 相关阅读:
    61. 最长不含重复字符的子字符串
    60. 礼物的最大价值 (未理解)
    59. 把数字翻译成字符串
    58. 把数组排成最小的数
    57. 数字序列中某一位的数字 (不懂)
    spring data jpa 官方文档
    idea 编译报错 源发行版 1.8 需要目标发行版 1.8
    idea maven 依赖报错 invalid classes root
    solr
    spring boot 官方文档
  • 原文地址:https://www.cnblogs.com/fugitive/p/13938020.html
Copyright © 2020-2023  润新知