验证码: 看不清楚,换一张 查询 注册会员,免验证
  • {{ basic.site_slogan }}
  • 打开微信扫一扫,
    您还可以在这里找到我们哟

    关注我们

使用stream的Collectors.toMap()方法常见问题如何解决

阅读:669 来源:乙速云 作者:代码code

使用stream的Collectors.toMap()方法常见问题如何解决

      使用stream的Collectors.toMap()方法常见问题

      java8开始的流式编程很大程度上简化了我们的代码,提高了开发效率。

      我们经常会使用到stream的Collectors.toMap()来将List转换Map

      在使用过程中有两个小坑需要注意

      1、java.lang.IllegalStateException: Duplicate key

      2、java.lang.NullPointerException

      第一个是由于在List转Map过程中Map集合的key重复导致的;

      第二个是由于在List转Map过程中Map集合的value有null导致的(当存在value值为空时,使用Collectors.toMap()会报NPE,因为底层调用了Map的merge方法,而map方法规定了此处的vlue不能为null,从而抛出空指针异常);

      解决方案

      1、Collectors.toMap(dto ->key值 , dto -> dto,(v1,v2) -> v1)

      在后面添加(v1,v2)->v1 指定选取第一个值 当key值重复的时候,根据情况而定选取第一个还是第二个)

      2、自定义一个Map来接收,不使用Collectors.toMap()

      使用stream的Collectors.toMap()方法常见问题如何解决

      第一种情况示例:

      import com.google.common.collect.Lists;
      import java.util.List;
      import java.util.Map;
      import java.util.stream.Collectors;
      import lombok.Data;
       
      public class Test {
       
          private static List userList = Lists.newArrayList();
       
          @Data
          public static class User {
              private String userCode;
              private String userName;
          }
       
          /**
           * 初始化数据
           * (这里的userCode=10002重复)
           */
          public static void initData() {
              User user1 = new User();
              user1.setUserCode("10001");
              user1.setUserName("张三");
       
              User user2 = new User();
              user2.setUserCode("10002");
              user2.setUserName("李四");
       
              User user3 = new User();
              user3.setUserCode("10002");
              user3.setUserName("王五");
       
              userList.add(user1);
              userList.add(user2);
              userList.add(user3);
          }
       
          public static void main(String[] args) {
              initData();
              //反例
            //  Map userMap = userList.stream().collect(Collectors.toMap(User::getUserCode, User::getUserName));
       
              //正例,在后面添加(u1,u2)->u1 指定选取第一个值 当key值重复的时候,根据情况而定选取第一个还是第二个
              Map userMap = userList.stream().collect(Collectors.toMap(User::getUserCode, User::getUserName, (u1, u2) -> u1));
       
              System.out.println(userMap);
          }
      }

      第二种情况示例:

      import com.google.common.collect.Lists;
      import java.util.HashMap;
      import java.util.List;
      import java.util.Map;
      import java.util.stream.Collectors;
      import lombok.Data;
       
      public class Test {
       
          private static List userList = Lists.newArrayList();
       
          @Data
          public static class User {
              private String userCode;
              private String userName;
          }
       
          /**
           * 初始化数据
           * (这里的userCode=10003的userName为空)
           */
          public static void initData() {
              User user1 = new User();
              user1.setUserCode("10001");
              user1.setUserName("张三");
       
              User user2 = new User();
              user2.setUserCode("10002");
              user2.setUserName("李四");
       
              User user3 = new User();
              user3.setUserCode("10003");
              user3.setUserName(null);
       
              userList.add(user1);
              userList.add(user2);
              userList.add(user3);
          }
       
          public static void main(String[] args) {
              initData();
              //反例
             // Map userMap = userList.stream().collect(Collectors.toMap(User::getUserCode, User::getUserName));
       
              //正例 (如果对转换后的顺序有要求,这里还可以使用LinkedHashMap)
              Map userMap = userList.stream().collect(HashMap::new, (map, user) -> map.put(user.getUserCode(), user.getUserName()), HashMap::putAll);
       
              System.out.println(userMap);
          }
       
      }

      Stream ToMap(Collectors.toMap) 实践

      Requirements

      List TO Map

      List Stream 转换 Map时向collect()方法中传递Collector对象,对象由Collectors.toMap()方法返回。

      如下实现List转换为Map

      List list = new ArrayList<>(
            Arrays.asList(
                    new GroupBrandCateBO("v1", "g1", "b1"),
                    new GroupBrandCateBO("v1", "g1", "b1"),
                    new GroupBrandCateBO("v3", "g3", "b3")
            )
      );
      Map map = list.stream().collect(Collectors.toMap(item -> item.getVersion(), item -> item.getGroupCode(), (oldVal, currVal) -> oldVal, LinkedHashMap::new)); 
      System.out.println(map.getClass());
      Map map0 = list.stream().collect(Collectors.toMap(item -> item.getVersion(), item -> item.getGroupCode(), (oldVal, currVal) -> oldVal));
      System.out.println(map0.getClass());
      System.out.println(map0.toString());
      Map map1 = list.stream().collect(Collectors.toMap(GroupBrandCateBO::getVersion, GroupBrandCateBO::getGroupCode));
      System.out.println(map1.toString());

      Console
      class java.util.LinkedHashMap
      class java.util.HashMap
      {v1=g1, v3=g3}
      Exception in thread “main” java.lang.IllegalStateException: Duplicate key g1
      at java.util.stream.Collectors.lambda$throwingMerger$0(Collectors.java:133)

      问题分析

      toMap()函数重载:

      • 未指定合并函数mergeFunction情况下,传入throwingMerger()返回BinaryOperator对象,当出现key重复时,调用合并函数!

      • 未指定Supplier实例情况下,默认生成HashMap实例。

      public static 
      Collector> toMap(Function keyMapper,
                                      Function valueMapper) {
          return toMap(keyMapper, valueMapper, throwingMerger(), HashMap::new);
      }
      
      public static 
      Collector> toMap(Function keyMapper,
                                      Function valueMapper,
                                      BinaryOperator mergeFunction) {
          return toMap(keyMapper, valueMapper, mergeFunction, HashMap::new);
      }
      
      public static >
      Collector toMap(Function keyMapper,
                                  Function valueMapper,
                                  BinaryOperator mergeFunction,
                                  Supplier mapSupplier) {
          BiConsumer accumulator
                  = (map, element) -> map.merge(keyMapper.apply(element),
                                                valueMapper.apply(element), mergeFunction);
          return new CollectorImpl<>(mapSupplier, accumulator, mapMerger(mergeFunction), CH_ID);
      }
      
      private static  BinaryOperator throwingMerger() {
          return (u,v) -> { throw new IllegalStateException(String.format("Duplicate key %s", u)); };
      }

      补充

      关于合并函数

      List list = new ArrayList<>(
             Arrays.asList(
                     new GroupBrandCateBO("v1", "g1", "b1"),
                     new GroupBrandCateBO("v1", "g2", "b2"),
                     new GroupBrandCateBO("v1", "g2", "b2"),
                     new GroupBrandCateBO("v3", "g3", "b3")
             )
      );
      Map map00 = list.stream().collect(Collectors.toMap(item -> item.getVersion(), item -> item.getGroupCode(), (oldVal, currVal) -> currVal));
      Map map01 = list.stream().collect(Collectors.toMap(item -> item.getVersion(), item -> item.getGroupCode(), (oldVal, currVal) -> oldVal + currVal));
      System.out.println(map00.toString());
      System.out.println(map01.toString());

      Console
      {v1=g2, v3=g3}
      {v1=g1g2g2, v3=g3}

      传入Lambda表达式将转化为BinaryOperator mergeFunction对象,合并处理value,非Key!!!

      比如:

      (oldVal, currVal) -> currVal) // key相同时当前值替换原始值
      (oldVal, currVal) -> oldVal + currVal //key相同时保留原始值和当前值
    分享到:
    *特别声明:以上内容来自于网络收集,著作权属原作者所有,如有侵权,请联系我们: hlamps#outlook.com (#换成@)。
    相关文章
    {{ v.title }}
    {{ v.description||(cleanHtml(v.content)).substr(0,100)+'···' }}
    你可能感兴趣
    推荐阅读 更多>

    {{ basic.bottom_text }}