基于多个“可选”条件的java过滤器hashmap

kninwzqo  于 2021-07-11  发布在  Java
关注(0)|答案(3)|浏览(377)

我有一个hashmap,需要在函数中过滤:

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

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

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() ?

gj3fmq9x

gj3fmq9x1#

这里有一个解决方案。它说明了不需要if语句序列。
您可以通过传递一组 predicate 来进一步改进filter。

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.function.Predicate;

public class FilterOption {
    public static void main(String... args) {
        FilterOption f = new FilterOption();

        System.out.println(f.theMap);
        f.filter(null, null);
        System.out.println(f.theMap);
        f = new FilterOption();
        f.filter(null, s -> s.startsWith("f"));
        System.out.println(f.theMap);
    }

    public FilterOption() {
        theMap.put("a", "foo");
        theMap.put("b", "bar");
    }

    Map<String, String> theMap = new HashMap<>();

    // assume we are filtering the values of the map
    // and assume that we keep the key if no filter
    // is false, and that a missing filter is true
    public void filter(Predicate<String> filterOption1,
                       Predicate<String> filterOption2) {
        List<Map.Entry<String, String>> entries =
                new ArrayList(theMap.entrySet());
        for (Map.Entry<String, String> entry : entries) {
            if (!keep(entry.getValue(), filterOption1)
                    || !keep(entry.getValue(), filterOption2)) {
                theMap.remove(entry.getKey());
            }
        }
    }

    private boolean keep(String value, Predicate<String> filterOption) {
        return filterOption == null || filterOption.test(value);
    }
}
kmbjn2e3

kmbjn2e32#

另一个解决方案是,如果您可以控制它,则不传递null。
如果您的方法希望获得某种过滤器,为什么要给它一个空值?这可以在调用方法中处理,如果调用方法不想过滤任何内容,则应该传递标识函数而不是null。

klsxnrf1

klsxnrf13#

您可以创建一些方法来接受 Predicate s、 连接非空元素并生成 Predicate s。然后你可以把这条链子传给 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);
}

相关问题