Apache Commons Collections

Posted by & filed under , , , .

I discovered this recently myself (having not been a big fan of Apache Commons Collections in the past) — and it’s a useful feature if you are dealing with a list of objects that can be compared by more than one property. For instance, consider you have a list of Person’s (see class below) which has a first name property, a surname and a date of birth. I suspect in most cases you will keep this list in memory sorted by surname — whenever you want to find the details of a certain person, you can do a binary search based on surname and voila, in log(N) you found your record (I am trying to exemplify why you would store the list sorted by surname — possibly not the best reason but would do!). What happens if you sometimes need to find for instance a person based on his/her first name? You could re-sort the list (using a different Comparator) based on first name, of course, but if your need to find a Person based on surname is constant (i.e. you need to do this a lot in your program then you do find it’s difficult to have to resort the list with a different comparator every time you switch in between finding people by first name or by surname.

There are of course multiple solutions to this problem — and each depends on the context of course — however, I found myself in the past having to traverse a list to look for a certain record — in the above example you can argue that you can keep the list sorted by surname but decide to traverse the list and compare just the first name for each item when retrieving persons based on first name (and of course, you can’t simply use Collections.find() and pass a different Comparator since the list is not sorted on first name!). If this involves just a single class, you can easily write a dedicated function to do that — if you find out that you have multiple lists with different classes that you have to traverse, you can of course use function overloading and provide different implementations, one for each class. A bit messy and not so “standard”…

Or you can use CollectionUtils.find in Commons Collections and supply a predicate! For instace (since the point of this is not demonstrating the correct usage of encapsulation I’ve decided to use public members everywhere — I’m being lazy!) :

public class Person {
  public String firstname;
  public String surname;
  public Date dob;
}
 
...
public class CheckFirstName implements Predicate {
  private String firstName;
 
  public CheckFirstName( Person firstName ) {
    this.firstName = firstName;
  }
 
  public boolean evaluate( Object o ) {
    if( o == null ) return false;
    if( !(o instanceof Person) ) return false;
    Person p = (Person)o;
    if( ObjectUtils.equals(p.firstname,firstName) )
      return true;
    return false;
  }
}
...
List myList;
...
String firstNameToFind = "John";
Predicate p = new CheckFirstName( firstNameToFind );
Person found = (Person)CollectionUtils.find( myList, p );