Wednesday, June 22, 2011

Java Generics.

What are generics?
Generics is a Java language feature which can be used to make code more robust (Errors can be identified at compile time as opposed to runtime.) and reusable (makes the code general, classic example includes Java Collection classes which heavily utilize Generics). More at link. Considering its benefits, I used it in my company's web project.

Usecase: Where Generics can be used?
Our web project had a java classes: ResultContainer (composed of List<Entry> where Entry is the pojo bean, totalResults stores the number of total results, totalPages int storing totalpages, currentPage int stores page number, DEFAULT_RESULT_SIZE =10) and ResultContainerHelper (supporting methods like getContainer and paginate etc). Following is the snippet of each.

//packages and imports.
public class ResultContainerHelper {

  public static ResultContainer getContainer(int pageNumber, int resultSize, List<Entry> entries) {
    //returns ResultContainer.
  }
  public static ResultContainer paginate(int pageNumber, List<Entry> entries, int entriesPerPage) {
    //returns Paginated ResultContainer object.
  }
}


//packages and imports.
public class ResultContainer {
  private List<Entry> entries = null;
  private int totalNumberOfResults;
  private int totalPages;
  private int currentPage = 1;
  public static final int DEFAULT_RESULT_SIZE = 10;

  public List<Entry> getEntries() {
    return entries;
  }
  public void setEntries(List<Entry> entries) {
    this.entries = entries;
  }
  //other accessor methods.
}


Rationale behind refactoring
This code is not usable, other than POJO bean Entry. The idea behind ResultContainer class is that it is a container and at a given time it holds a list of values of some type, why does it have to be list of Entry in this case. Note the code can be easily changed to List<Object> but  by doing so we make the code more brittle (note: would be prone to adding any object to this collection). Generics come to the rescue...

Refactored code

//packages and import statments.

public class ResultContainerHelper {

  public static <T> ResultContainer getContainer(int pageNumber, int resultSize, List<T> entries) {
    return resultContainer;
  }
  public static <T> ResultContainer paginate(int pageNumber, List<T> entries, int entriesPerPage) {

    ResultContainer container = ResultContainerHelper.getContainer(pageNumber, entriesPerPage, entries);
    container = ResultContainerHelper.pagination(container, pageNumber, entriesPerPage);
    return container;

  }
}


public class ResultContainer<T> {
  private List<T> entries = null;
  private int totalNumberOfResults = 0;
  private int totalPages = 0;
  private int currentPage = 1;
  public static final int DEFAULT_RESULT_SIZE = 10;

  public List<T> getEntries() {
    return entries;
  }

  public void setEntries(List<T> entries) {
    this.entries = entries;
  }
  //other accessor methods.
}


Advantages 
1) Refactored code is more reusable (any POJO bean can be used)
2) More robust (at given time, we are sure a collection of a given type would exist)
3) Codebase didn't expand. i.e. I didn't write any new classes for my needs.


Conclusion
A friendly advice: do not code blindly! If given a little thought before coding, it helps save lot of time and maintains code base relatively clean.

1 comment:

  1. Way to go Amrut. Yeah, striving to do best practices in coding no matter how urgent a task is leads one to internalize good techniques and soon comes as second nature. Refactoring is always divine =).

    Keep it coming, learning here as well.

    ReplyDelete