Jason
Jason

Reputation: 4130

Guava Predicate Failing To Filter Collection

I have the following method to use a Predicate to filter a collection, throwing out any members where propertyName isn't in a given list of allowed values. It uses Common-BeanUtils to extract a value from the object, and that value has to be a String:

public static <T> void filterListByStringPropertyWithAllowableValues(List<T> listToFilter, 
        final String propertyName, 
        final List<String> allowedValues) {

    Predicate<T> allowedValuesPredicate = new Predicate<T>() {

        @Override
        public boolean apply(T arg0) {

            String value;
            boolean result = false;
            try {
                value = BeanUtils.getProperty(arg0, propertyName);
                System.out.println(value);
                result = allowedValues.contains(value);
            } catch (IllegalAccessException e) {
                e.printStackTrace();
            } catch (InvocationTargetException e) {
                e.printStackTrace();
            } catch (NoSuchMethodException e) {
                e.printStackTrace();
            } 

            return result;


        }
    };

    Iterables.filter(listToFilter, allowedValuesPredicate);

}

Unfortunately, my test fails utterly.

@Test
public void testfilterListByStringPropertyWithAllowableValues() throws Exception {

    TestClass item1 = new TestClass("value1","whatever1");
    TestClass item2 = new TestClass("value2","whatever2");
    TestClass item3 = new TestClass("value3","whatever3");

    List<TestClass> initialList = Lists.newArrayList(item1, item2, item3);

    MyCollectionUtils.filterListByStringPropertyWithAllowableValues(initialList, "importantField", 
            Lists.newArrayList("value1","value2"), 3);

    assertTrue("Collection size should be 2. Actual: " + initialList.size(), initialList.size() == 2);
}

Am I making an incredibly stupid mistake here?

Update: working code is below.

public static <T> List<T> filterListByStringPropertyWithAllowableValues(List<T> listToFilter, 
        final String propertyName, 
        final Set<String> allowedValues) {

    Predicate<T> allowedValuesPredicate = new Predicate<T>() {

        @Override
        public boolean apply(T arg0) {

            String value;
            boolean result = false;
            try {
                value = BeanUtils.getProperty(arg0, propertyName);
                System.out.println(value);
                result = allowedValues.contains(value);
            } catch (IllegalAccessException e) {
                e.printStackTrace();
            } catch (InvocationTargetException e) {
                e.printStackTrace();
            } catch (NoSuchMethodException e) {
                e.printStackTrace();
            } 

            return result;

        }
    };

    return Lists.newArrayList(Iterables.filter(listToFilter, allowedValuesPredicate));

}

Upvotes: 1

Views: 481

Answers (1)

JB Nizet
JB Nizet

Reputation: 691765

Yes, you're doing an incredibly stupid mistake ;-)

You're not returning the filtered list. filter() doesn't modify the given list. It returns a filtered Iterable.

Also, allowedValues should be a HashSet rather than a List. That would make your filter more efficient. HashSet.contains() runs in constant time, whereas List.contains() is O(n).

Upvotes: 5

Related Questions