Java流:添加到地图但避免变异

Che*_*toy 5 java grouping dictionary java-8 java-stream

我经常发现自己处于需要Map从Set或者创建对象的情况List.键通常是一些String或Enum等,值是一些新数据集中在一起的新对象.对我来说,这样做的通常方法是首先创建Map<String, SomeKeyValueObject>,然后迭代我进入的Set或List并改变我新创建的地图.

如下例所示:

class Example {
   Map<String, GroupedDataObject> groupData(final List<SomeData> list){
      final Map<String, GroupedDataObject> map = new HashMap<>();
      for(final SomeData data : list){
         final String key = data.valueToGroupBy();
         map.put(key, GroupedDataObject.of(map.get(key), data.displayName(), data.data()));
      }
      return map;
   }

}

class SomeData {
   private final String valueToGroupBy;
   private final Object data;
   private final String displayName;

   public SomeData(final String valueToGroupBy, final String displayName, final Object data) {
      this.valueToGroupBy = valueToGroupBy;
      this.data = data;
      this.displayName = displayName;
   }

   public String valueToGroupBy() {
      return valueToGroupBy;
   }

   public Object data() {
      return data;
   }

   public String displayName() {
      return displayName;
   }
}

class GroupedDataObject{

   private final String key;
   private final List<Object> datas;

   private GroupedDataObject(final String key, final List<Object> list) {
      this.key = key;
      this.datas = list;
   }

   public static GroupedDataObject of(final GroupedDataObject groupedDataObject, final String key, final Object data) {
      final List<Object> list = new ArrayList<>();
      if(groupedDataObject != null){
         list.addAll(groupedDataObject.datas());
      }
      list.add(data);
      return new GroupedDataObject(key, list);
   }

   public String key() {
      return key;
   }

   public List<Object> datas() {
      return datas;
   }
}
Run Code Online (Sandbox Code Playgroud)

这感觉非常不洁净.我们创建一个地图,然后一遍又一遍地改变它.

我喜欢java 8s使用Streams并创建非变异数据结构(或者更确切地说,你没有看到变异).那么有没有办法将这种数据分组转换为使用声明式方法而不是命令式方法?

我试图在/sf/answers/2411767011/中实施该建议,但我似乎磕磕绊绊.使用答案中的方法(使用Collectors.groupingBy和的建议Collectors.mapping)我能够将数据分类到地图中.但我无法将"数据"分组到同一个对象中.

有没有办法以声明的方式做到这一点,还是我坚持要求?

Era*_*ran 5

您可以使用Collectors.toMap合并功能而不是Collectors.groupingBy.

Map<String, GroupedDataObject> map =
    list.stream()
        .collect(Collectors.toMap(SomeData::valueToGroupBy,
                                  d -> {
                                     List<Object> l = new ArrayList<>();
                                     l.add(d.data());
                                     return new GroupedDataObject(d.valueToGroupBy(), l);
                                  },
                                  (g1,g2) -> {
                                      g1.datas().addAll(g2.datas());
                                      return g1;
                                  }));
Run Code Online (Sandbox Code Playgroud)

GroupedDataObject构造函数必须为了这个工作进行访问.