Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/312.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/jsf-2/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java 将列表转换为映射并筛选空键_Java_Java 8_Java Stream_Collectors - Fatal编程技术网

Java 将列表转换为映射并筛选空键

Java 将列表转换为映射并筛选空键,java,java-8,java-stream,collectors,Java,Java 8,Java Stream,Collectors,使用Java8流,我想将列表转换为一个映射,如解决方案中所述。但是,我希望筛选以删除具有特定键的条目(例如,如果键为null),而无需将值转换为键两次 例如,我可以在收集之前进行过滤,例如 Map<String, Choice> result = choices.stream().filter((choice) -> choice.getName() != null).collect(Collectors.toMap(Choice::getName,

使用Java8流,我想将列表转换为一个映射,如解决方案中所述。但是,我希望筛选以删除具有特定键的条目(例如,如果键为null),而无需将值转换为键两次

例如,我可以在收集之前进行过滤,例如

Map<String, Choice> result =
    choices.stream().filter((choice) -> choice.getName() != null).collect(Collectors.toMap(Choice::getName,
                                 Function.<Choice>identity());
映射结果=
choices.stream().filter((choice)->choice.getName()!=null).collect(Collectors.toMap(choice::getName,
Function.identity());
在我的例子中,获取密钥的逻辑比简单地获取字段属性更复杂,我希望避免先在过滤器中执行逻辑,然后在Collectors.toMap的keyMapper函数中执行逻辑


如何使用自定义键映射器函数将列表转换为映射,并根据新键过滤某些值?

如果只想计算一次键,可以使用流方法映射将流转换为元组流,根据键过滤元组,最后从元组创建映射:

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()));
Map result=choices.stream()
.map(c->newAbstractMap.SimpleEntry(c.getName(),c))
.filter(e->e.getKey()!=null)
.collect(toMap(e->e.getKey(),e->e.getValue());

这里有一个定制的收集器,可以满足您的需求:

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;
    }
}
公共类FilteredKeyCollector实现收集器{

private final Function如果您接受分两步执行,您可以先收集地图,然后删除不需要的密钥:

Map result=choices.stream()
.collect(Collectors.toMap(c->c.getName(),c->c);
result.keySet().removeIf(k->k==null);

Is
choice.getName()
实际上这是一个昂贵的操作?如果不是,那么任何喜欢的人最终可能都会比这个简单的解决方案慢。在目前的情况下,这并不特别昂贵,但如果有其他选择,例如编写自定义收集器或使用不同的收集器,我希望避免不得不做两次stream方法比collect方法(如map)更适合首先将每个项目转换为map.Entry。不过,如果可能的话,我希望不必创建自定义的“中间”对对象。在我看来,似乎没有任何简单的选项不涉及中间对,而且创建中间对的成本比只创建中间对要高调用一个简单的getter.Map.Entry不是抽象的吗?@CarrKnight:你是对的,我用
AbstractMap.SimpleEntry
替换了
Map.Entry
。我理解最终的
收集器。toMap()
这在这个星座中是必要的,但我忍不住想,一定有可能重写并简化这个表达式,以便将其分解。这可能是因为我的直觉告诉我这里有开销。但也许没有?
Map<String, Choice> result = choices.stream()
    .collect(new FilteredKeyCollector<>(
                Choice::getName,    // key mapper
                c -> c,             // value mapper
                k -> k != null));   // key filter