首页 > 解决方案 > 根据多个“可选”条件过滤 HashMap

问题描述

我有一个需要在函数中过滤的 HashMap:

public void filter(filterOption1, filterOption2, filterOption3, filterOption4) {
    //Filter map in here
    ...
} 

过滤器选项filterOption1, filterOption2, filterOption3,filterOption4可能在运行时为空,而我希望避免的是:

public void filter(filterOption1, filterOption2, filterOption3, filterOption4) {
    if(filterOption1 != null && filterOption2 == null && filterOption3 == null && filterOption4 == null) {
        // Filter map values on filterOption1
    } else if(filterOption1 != null && filterOption2 != null && filterOption3 == null && filterOption4 == null) {
        // Filter map values on filterOption1 and filterOption2
    } else if ... // And so on
    
} 

有没有办法通过一些巧妙的过滤来避免链接 16 个 if 语句map.stream()

标签: javacollectionshashmapjava-streamfiltering

解决方案


您可以创建一些接受 s 数组Predicate、连接非空元素并生成Predicates 链的方法。然后你可以将此链传递给filter方法:

public static void main(String... args) {
    Map<Character, Character> map =
            Map.of('a', 'A', 'b', 'B', 'c', 'C', 'd', 'D');

    // predicate chain 'and'
    Map<Character, Character> filtered1 = map.entrySet().stream()
            .filter(predicateChain(Predicate::and,
                    e -> e.getKey() > 'a', null,
                    e -> e.getValue() < 'D', null))
            .collect(Collectors.toMap(
                    Map.Entry::getKey, Map.Entry::getValue));

    System.out.println(filtered1); // {b=B, c=C}

    // predicate chain 'or'
    Map<Character, Character> filtered2 = map.entrySet().stream()
            .filter(predicateChain(Predicate::or,
                    e -> e.getKey() < 'b', null,
                    e -> e.getValue() > 'C', null))
            .collect(Collectors.toMap(
                    Map.Entry::getKey, Map.Entry::getValue));

    System.out.println(filtered2); // {a=A, d=D}
}
@SafeVarargs
public static <T> Predicate<T> predicateChain(
        BinaryOperator<Predicate<T>> accumulator,
        Predicate<T>... predicates) {
    return Stream.of(predicates)
            // non-null predicates
            .filter(Objects::nonNull)
            // concatenation of predicates
            .reduce(accumulator)
            .orElse(p -> true);
}

推荐阅读