StreamAPI Collectors.groupingBy为空集合而不是null

时间:2016-10-12 13:51:04

标签: java java-8 java-stream

List<Entity> entities = ...
Map<Boolean, List<Entity>> entitiesByIsTest = entities.stream()
                        .collect(Collectors.groupingBy(Entity::isTest));

很明显,结果图具有分组属性中唯一的键。对于具有不定值集的类型,它必须像这样工作。但是enums / booleans /其他确定的类型呢?

是否可以比下面的片段更优雅地实现空集合的初始化?

if (entitiesByIsTest.get(true) == null) {
    entitiesByIsTest.put(true, new ArrayList());
}

4 个答案:

答案 0 :(得分:8)

如果您想要Boolean个键并且两个映射始终都已初始化,请使用partitioningBy,它具有所需的属性。

Map<Boolean, List<Entity>> entitiesByIsTest = entities.stream()
                        .collect(Collectors.partitioningBy(Entity::isTest));

如果密钥是enum,则必须使用groupingBy,但您可以使用

替换后续的get操作
List<Entity> value=map.computeIfAbsent(key, x->new ArrayList<>());

当且仅当没有先前的映射时才会构造并放置一个新的ArrayList,并且在任何一种情况下返回实际的映射值(与putIfAbsent不同)。

当然,您可以在一个急切的操作中添加所有缺席值:

EnumSet.allOf(KeyType.class).forEach(key->map.computeIfAbsent(key, x->new ArrayList<>()));

答案 1 :(得分:5)

你可以使用entitiesByIsTest.putIfAbsent(true,new ArrayList());,只有当地图中没有任何内容时才会添加新的空广告

答案 2 :(得分:0)

你可以写自己的收藏家。

Collectors.of(
   //**Initialize map with all of your values**//,
   entity -> map.get(entity.isTest()).add(entity),
   (left, right) -> right.forEach(r -> left.get(r.getKey()).addAll(r.getValue)); return r;)

答案 3 :(得分:0)

只需传入已经包含空列表的地图供应商作为所有期望键的值即可。

这应该按枚举元素分组:

Map<Type, List<Value>> emptyMap = EnumSet.allOf(Type.class)
                .stream()
                .collect(toMap(identity(), f -> new ArrayList<>()));
Function<Value, Type> fun = this::groupByType;
Map<Type, List<Value>> groups = values.stream()
                .collect(groupingBy(fun, () -> emptyMap, toList()));