Google

Nov 13, 2012

Coding in Java -- working with a List



Q. Can you write code to create sub lists for a given source list based on the supplied predicate?

For example, the source list might have numbers [1,2,3,4,5,6,7,8,9,10] and the sub list created might include

predicate: even numbers --> [2,4,6,8] (predicate means --> declare condition)
prdeicate: factor of 5  -->  [5, 10]


The code should be written such a way that it uses the best practices, easy to extend in the future, and maintainable.

A. This can be done a number of ways. The following code snippets take following key aspects into consideration.


1. Use generics.

2. Code to interface.

3. Make it extendable. New predicate implementation classes can be easily added in the future like OddNumberPrdeicate, PrimeNumberPredicate, etc and no change is required to the FilteredList class. It just takes a source list and a predicate implementation as arguments to create a sublist. If you need to build
heirachy of sublists, you can add a parent field in FilteredList class to maintain a hierachy.

4. Easy to test. The JUnit test classes are provided to test the FilteredList and the Predicate classes. Both happy path and exceptional paths are tested.

5. Composition is favored over inheritance hence the FilteredList was not defined as public class FilteredList extends List, instead the sublists was composed within FilteredList.

Here is the sample code.

Step 1: Define the Predicate interface

public interface Predicate<E> {
 boolean evaluate(E object);
}


Step 2: Define the implementation classes for the Predicate interface. One for filtering even numbers and another one for filtering factors of five.

public class EvenNumberPredicate implements Predicate<Integer> {

 @Override
 public boolean evaluate(Integer number) {
  return (number % 2 == 0) ? true : false;
 }

}


public class FactorOfFivePredicate implements Predicate<Integer> {

 @Override
 public boolean evaluate(Integer number) {
  return (number % 5 == 0) ? true : false;
 }

}


Step 3: Define the FilteredList interface and the implementation class.

import java.util.List;

public interface FilteredData<E> {
 abstract List<E> getSubData(List<E> sourceData);
}


import java.util.ArrayList;
import java.util.Collections;
import java.util.List;

public class FilteredList<E> implements FilteredData<E> {
 
  private Predicate<E> predicate = null;
 
  public FilteredList(Predicate<E> predicate) {
  if (predicate == null) {
   throw new IllegalArgumentException("Expected to receive a non-null predicate on which to base the sublist!");
  }

  this.predicate = predicate;
 }

 public Predicate<E> getPredicate() {
  return predicate;
 }

 @Override
 public List<E> getSubData(List<E> sourceData) {
  List<E> subData = null;
  
  //return empty data
  if (sourceData == null || sourceData.isEmpty()) {
   subData = Collections.emptyList();
  }
        //return filtered data
  else {
   subData = new ArrayList<E>(sourceData.size());
   // Evaluate each item in the source to create the sublist...
   for (E item : sourceData) {
    if (predicate.evaluate(item)) {
     subData.add(item);
    }
   }
  }
  
  return subData;
 }
}




Step 4: Finally the JUnit class to test both positive and negative scenarios.

import java.util.Arrays;
import java.util.List;

import junit.framework.Assert;

import org.junit.Before;
import org.junit.Test;

public class FilteredListTest {
 
 private List<Integer> listOfIntegers;
 
 
 @Before
 public void init(){
  listOfIntegers = Arrays.asList(1,2,3,4,5,6,7,8,9,10);
 }
 
 @Test
 public void testEvenNumbers(){
  Predicate<Integer> predicate = new EvenNumberPredicate();
  FilteredData<Integer> list = new FilteredList<Integer>(predicate);
  Assert.assertTrue(list.getSubData(listOfIntegers).size() == 5) ;
  Assert.assertEquals(Arrays.asList(2,4,6,8,10), list.getSubData(listOfIntegers));
 }
 
 @Test
 public void testFactorOfFiveNumbers(){
  Predicate<Integer> predicate = new FactorOfFivePredicate();
  FilteredData<Integer> list = new FilteredList<Integer>( predicate);
  Assert.assertTrue(list.getSubData(listOfIntegers).size() == 2) ;
  Assert.assertEquals(Arrays.asList(5,10), list.getSubData(listOfIntegers));
 }

 
 @Test(expected = IllegalArgumentException.class)
 public void testExceptionalCondition1(){
  new FilteredList<Integer>(null);
 }
 
 @Test
 public void testExceptionalCondition2(){
  Predicate<Integer> predicate = new FactorOfFivePredicate();
  FilteredData<Integer>  list = new FilteredList<Integer>(predicate);
  Assert.assertTrue(list.getSubData(null).size() == 0);
 }
 
}


Labels: ,

1 Comments:

Blogger sumanth said...

Hi Arulkumaran,
I'm having 5+ yrs exp in Java,J2EE technology. Can you let me know some java tricky interview questions ?

11:25 PM, February 13, 2014  

Post a Comment

Subscribe to Post Comments [Atom]

<< Home