Question

Imagine a class like shown below. I have to write some code which can sum up all values of a collection and of all values which satisfy a given criterion.

class MyClass {
    private String name;
    private int value;
}

My current code looks like this. Is there more elegant design pattern for the following functionality?

public static int sumFilter(Collection<MyClass> collection, String filter) {
   int result = 0;
   for (MyClass myClass : collection) {
       if (filter == null || filter.equals(myClass.getName()) {
           result += myClass.getValue();
       }
   }
   return result;
}

public static int sumAll(Collection<MyClass> collection) {
   return sumFilter(collection, null);
}
Was it helpful?

Solution

An improvement to your existing approach :

You could add more flexibility to your filtering rules by using Filter as an interface (and having to add more code ) - very similar to applying different comparison rules when calling Collections.sort methods with custom Comparator, for instance something like :

interface Filter<T> {
    boolean include(T item);

    public final static Filter<Object> INCLUDE_ALL = new Filter<Object>() {
        @Override
        public boolean include(Object item) {
            return true; /* includes everything unconditionally */
        }
    };
}



public static int sumFilter(Collection<MyClass> collection, 
        Filter<? super MyClass> filter) {

    int result = 0;
    if (filter == null) {
        filter = Filter.INCLUDE_ALL;
    }
    for (MyClass item : collection) {
        if (filter.include(item)) {
            result += item.value;
        }
    }
    return result;
 }

public static int sumAll(Collection<MyClass> collection) {
    return sumFilter(collection, Filter.INCLUDE_ALL);
}

Then you could have custom filters with more complex rules (rather than just String.equals like in your example), for instance matching against regex :

    new Filter<MyClass>() {

        @Override
        public boolean include(MyClass item) {
            return item.getName().matches("some regex");
        }
    };

OTHER TIPS

There is more elegant solution if you're using Java 8, stream-based:

List<MyObj> collection = ...; //initialization;

int sum = 0;
collection.stream()
    .filter(obj -> filter != null ? obj.getValue().equals(filter) : true)
    .mapToInt(obj -> obj.getIntValue()).sum();
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top