Search This Blog

Friday, February 02, 2007

What are some of the best practices relating to Java collection?

Use ArrayLists, HashMap etc as opposed to Vector, Hashtable etc, where possible to avoid any
synchronization overhead. Even better is to use just arrays where possible. If multiple threads concurrently
access a collection and at least one of the threads either adds or deletes an entry into the collection,
then the collection must be externally synchronized. This is achieved by:

List myList = Collections.synchronizedList (myList);

Map myMap = Collections.synchronizedMap (myMap);

Set the initial capacity of a collection appropriately (e.g. ArrayList, HashMap etc). This is because collection
classes like ArrayList, HashMap etc must grow periodically to accommodate new elements. But if you have a very large array, and you know the size in advance then you can speed things up by setting the initial size
appropriately.

HashMaps/Hashtables need to be created with sufficiently large capacity to minimise
rehashing (which happens every time the table grows). HashMap has two parameters initial capacity and
load factor that affect its performance and space requirements. Higher load factor values (default load factor
of 0.75 provides a good trade off between performance and space) will reduce the space cost but will
increase the lookup cost of myMap.get(…) and myMap.put(…) methods. When the number of entries in the
HashMap exceeds the current capacity * loadfactor then the capacity of the HasMap is roughly doubled by
calling the rehash function. It is also very important not to set the initial capacity too high or load factor too
low if iteration performance or reduction in space is important.

Avoid where possible

The code below is hard to maintain and understand by
others. Also gets more complicated as the requirements
grow in the future because we are throwing different
types of objects like Integer, String etc into a list just
based on the indices and it is easy to make mistakes
while casting the objects back during retrieval.

List myOrder = new ArrayList()
ResultSet rs = …
While (rs.hasNext()) {
List lineItem = new ArrayList();
lineItem.add (new Integer(rs.getInt(“itemId”)));
lineItem.add (rs.getString(“description”));
….
myOrder.add( lineItem);
}
return myOrder;

Example 2:
List myOrder = new ArrayList(10);
//create an order
OrderVO header = new OrderVO();
header.setOrderId(1001);

//add all the line items
LineItemVO line1 = new LineItemVO();
line1.setLineItemId(1);
LineItemVO line2 = new LineItemVO();
Line2.setLineItemId(2);

Better approach


When storing items into a collection define value objects as shown
below:

(VO is an acronym for Value Object).


public class LineItemVO {
private int itemId;
private String productName;
public int getLineItemId(){return accountId ;}
public int getAccountName(){return accountName;}
public void setLineItemId(int accountId ){
this.accountId = accountId
}
//implement other getter & setter methods
}


Now let’s define our base wrapper class, which represents an order:


public abstract class Order {
int orderId;
List lineItems = null;
public abstract int countLineItems();
public abstract boolean add(LineItemVO itemToAdd);
public abstract boolean remove(LineItemVO itemToAdd);
public abstract Iterator getIterator();
public int getOrderId(){return this.orderId; }
}
Now a specific implementation of our wrapper class:
public class OverseasOrder extends Order {
public OverseasOrder(int inOrderId) {
this.lineItems = new ArrayList(10);
this.orderId = inOrderId;
}