Search code examples
javalambdajava-8functional-programmingpredicate

How to iterate a list of Predicates


I have a spring boot application and we have an application.yml with a set of feature flags on it

featureFlag:
    featureOne:true
    featureTwo:true
    featureThree:true
    featureFour:false

Then this file is read by a this class

@Configuration
@ConfigurationProperties(prefix="featureFlag")
public class FeatureFlag{

private Boolean featureOne;
private Boolean featureTwo;
private Boolean featureThree;
private Boolean featureFour;
/*The predicates based on the feature flags*/

private Predicate<FeatureFlag> isFeatureFlagOneEnabled = featureFlag.isFeatureOne();
private Predicate<FeatureFlag> isFeatureFlagTwoEnabled = featureFlag.isFeatureTwo();
private Predicate<FeatureFlag> isFeatureFlagThreeEnabled = featureFlag.isFeatureThree();
private Predicate<FeatureFlag> isFeatureFlagFourEnabled = featureFlag.isFeatureFour();
}

I want to pass the actual predicate and iterate each one of them but I want to know if I can do a generic function that I pass the list of Predicates with its value to be tested and if all of them are true the function return me a true otherwise false

Then in this class add some code like this because I want to generate this list on demand, for example I have a client x that purchase featureOne and featureTwo, in this example I create a list like this

Set<Predicate<FeatureFlag>> rulesForClientX = new HashSet<>();
rulesForClientX.add(isFeatureFlagOneEnabled);
rulesForClientX.add(isFeatureFlagTwoEnabled);

Then I want to create a specific logic for that client and pass it the list of predicates previously created, but I think I would need something like this

Function<List<Predicate<FeatureFlag>>, Boolean> iteratePredicates = (predicates) -> { 
    //test each predicate and return true if all of them are true otherwise return false
}

Solution

  • Chain Predicates

    What you should look forward to is chaining the predicates that you have.

    I pass the list of Predicates with its value to be tested and if all of them are true the function return me a true otherwise false

    Based on your requirements this should look like;

    public Predicate<FeatureFlag> chainPredicates(Set<Predicate<FeatureFlag>> predicates) {
        return predicates.stream()
                         .reduce(Predicate::and) // all true
                         .orElse(p -> false); // or false
    }
    

    Consume Predicate

    Further now, you can consume this single Predicate easily as

    boolean testFeatureFlag(Set<Predicate<FeatureFlag>> predicates, FeatureFlag value) {
        return chainPredicates(predicates).test(value);
    }
    

    or on a collection say a List<FeatureFlag> to filter out specific FeatureFlags as:

    List<FeatureFlag> selectiveFeatures(Set<Predicate<FeatureFlag>> predicates, List<FeatureFlag> featureFlags) {
        Predicate<FeatureFlag> flagPredicate  = chainPredicates(predicates);
        return featureFlags.stream()
                .filter(flagPredicate)
                .collect(Collectors.toList());
    }