Externalizing a predicate in Java Lambda Stream Filter

I have an ArrayList of a data model that has 10 fields based on user input. I need to dynamically apply a Predicate condition on a user selected field for a Stream filter.

Below snippet applied with one of the itemDesc fields, but at runtime the user can select any field.

Predicate<DataModel> contains = (n) -> n.getItemDesc().contains(query);        
List filtered = data.stream().filter(contains).collect(Collectors.toList());

      

Basically we need to construct the predicate dynamically instead of the predefined, is it possible, if so, any examples. Thanks in advance.

+3


source to share


1 answer


It depends on how dynamic the solution needs to be. For ten properties, it may be acceptable to have an explicit list of properties at compile time rather than dynamic (reflective) detection.

Declaring the available properties might look like

enum DataModelProperty {
    ITEM_DESC(DataModel::getItemDesc),
    FOO(DataModel::getFoo),
    BAR(DataModel::getBar)
    // the other seven properties…
    ;
    final Function<DataModel,String> getter;

    private DataModelProperty(Function<DataModel, String> f) {
        getter = f;
    }
    public Function<DataModel, String> getPropertyGetter() {
        return getter;
    }
    public Predicate<DataModel> asPredicate(String query) {
        return n -> getter.apply(n).contains(query);
    }
}

      



You can then use DataModelProperty.values()

it to present the user with a list of choices as well as persisting String

through Enum.name()

and possibly restoring a runtime object through DataModelProperty.valueOf(String)

.

Once you have a property selected, it's easy to use for filtering

DataModelProperty p=DataModelProperty.valueOf("ITEM_DESC");// just as example

List<DataModel> filtered = data.stream()
                               .filter(p.asPredicate(query))
                               .collect(Collectors.toList());

      

+3


source







All Articles