使用java 8流我想将列表转换为地图,如Java 8 List<V> into Map<K, V>的解决方案中所述。但是,我想过滤以删除具有某些键的条目(例如,如果键为空),而不将值转换为键两次。
例如,我可以在收集之前进行过滤,例如
Map<String, Choice> result =
choices.stream().filter((choice) -> choice.getName() != null).collect(Collectors.toMap(Choice::getName,
Function.<Choice>identity());
在我的例子中,获取密钥的逻辑比简单地获取字段属性更复杂,我想避免在过滤器中首先执行逻辑,并且再次在Collectors.toMap的keyMapper函数中执行
如何使用自定义keyMapper函数将列表转换为地图并根据新密钥过滤某些值?
答案 0 :(得分:8)
如果只想计算一次键,可以使用流方法 map 将流转换为元组流,根据该元素过滤元组key,最后从元组创建地图:
Map<String, Choice> result = choices.stream()
.map(c -> new AbstractMap.SimpleEntry<String, Choice>(c.getName(), c))
.filter(e -> e.getKey() != null)
.collect(toMap(e -> e.getKey(), e -> e.getValue()));
答案 1 :(得分:2)
这里是您想要的自定义收藏家:
public class FilteredKeyCollector<T, K, V> implements Collector<T, Map<K, V>, Map<K, V>> {
private final Function<? super T,? extends K> keyMapper;
private final Function<? super T,? extends V> valueMapper;
private final Predicate<K> keyFilter;
private final EnumSet<Collector.Characteristics> characteristics;
private FilteredKeyCollector(Function<? super T,? extends K> keyMapper, Function<? super T,? extends V> valueMapper, Predicate<K> keyFilter) {
this.keyMapper = keyMapper;
this.valueMapper = valueMapper;
this.keyFilter = keyFilter;
this.characteristics = EnumSet.of(Collector.Characteristics.IDENTITY_FINISH);
}
@Override
public Supplier<Map<K, V>> supplier() {
return HashMap<K, V>::new;
}
@Override
public BiConsumer<Map<K, V>, T> accumulator() {
return (map, t) -> {
K key = keyMapper.apply(t);
if (keyFilter.test(key)) {
map.put(key, valueMapper.apply(t));
}
};
}
@Override
public BinaryOperator<Map<K, V>> combiner() {
return (map1, map2) -> {
map1.putAll(map2);
return map1;
};
}
@Override
public Function<Map<K, V>, Map<K, V>> finisher() {
return m -> m;
}
@Override
public Set<Collector.Characteristics> characteristics() {
return characteristics;
}
}
使用它:
Map<String, Choice> result = choices.stream()
.collect(new FilteredKeyCollector<>(
Choice::getName, // key mapper
c -> c, // value mapper
k -> k != null)); // key filter
答案 2 :(得分:1)
如果您接受分两步操作,则可以先收集地图,然后删除不需要的密钥:
Map<String, Choice> result = choices.stream()
.collect(Collectors.toMap(c -> c.getName(), c -> c);
result.keySet().removeIf(k -> k == null);