Filter collection by class type

This example will demonstrates how to filter a collection by a java class type using java, java 8, guava and apache commons.

Setup

List<Object> objects;
    
@Before
public void setUp () {
    objects = Lists.newArrayList();
    
    objects.add(new Integer(15));
    objects.add(new Double(12));
    objects.add("hello");
    objects.add(Lists.newArrayList());
    objects.add(Maps.newConcurrentMap());
    objects.add("world");
}

Straight up Java

Until Java 8, the jdk did not have a way to filter a collection unless you iterate over the collection and then apply criteria. In the snippet below, we will use a enhanced for loop using the instanceOf keyword to check if it is of class String.

@Test
public void filter_elements_by_type_java () {
    
    List<String> strings = new ArrayList<String>();
    
    for (Object obj : objects) {
        
        if (obj instanceof String) {
            strings.add((String) obj); 
        }
    }
    
    assertThat(strings, contains(
            "hello", "world"));
}

Java 8

Java 8 introduced the stream api which allows you to write powerful code in just a few lines. Streams filter is an intermediate operation that will return a stream consisting of the elements that match the specified predicate. In the snippet below, through a lambda expression we will create a java predicate that will filter elements where the class type equals a string.

@Test
public void filter_elements_by_type_java8_lambda () {
    
    List<String> strings = objects
            .stream()
            .filter(p -> p instanceof String)
            .map(p -> (String) p)
            .collect(Collectors.toList());

    System.out.println(strings);
    
    assertThat(strings, contains(
            "hello", "world"));
}

Google Guava

Both guava Iterables and FluentIterable utility class contain an overloaded filter method that accepts a Class type parameter. It will return all elements from the collection equaling the parameter type.

Using FluentIterable

@Test
public void filter_elements_by_type_guava_fluentiterable () {
    
    List<String> strings = FluentIterable.from(objects)
        .filter(String.class)
        .toList();
    
    assertThat(strings, contains(
            "hello", "world"));
}

Using Iterables

@Test
public void filter_elements_by_type_iterable () {
    
    Iterable<String> strings = Iterables.filter(objects, String.class);
    
    assertThat(strings, contains(
            "hello", "world"));
}

Apache Commons

Similar to java and guava predicate, apache commons has a predicate class as well. Below we will call CollectionsUtils.filter passing it a predicate that will return true if the object is of class type String and it will remove the elements where it doesn't match this criteria.

@Test
public void filter_elements_by_type_apache () {
    
    CollectionUtils.filter(objects, new org.apache.commons.collections.Predicate() {
        public boolean evaluate(Object obj) {
            return obj instanceof String;
        }
    });
    
    @SuppressWarnings("unchecked")
    Collection<String> strings = CollectionUtils.typedCollection(objects, String.class);
    
    assertThat(strings, contains(
            "hello", "world"));
}