Best Practices and Serialization with the Collections API

Here is an attempt to resolve a conflict with some best practices. Input is definitely welcome.

Updated: 28 January, 2007

One best practice, all variables should be declared with the most generic type possible. For example, if we have an ArrayList in a class, we should declare it as a List (see Effective Java, item 34: Refer to objects by their interfaces; or Java Practices: Use interface references to Collections ).

private List myList = new ArrayList();

Simple enough. We all do it, right? Good.

Here's another. Every field of a serializable class must be either serializable or transient (of course, some folks haven't quite figured out the transient keyword). Pretty logical, makes for clear maintainable code (see Advanced Serialization or Durable Java: Serialization ) .

public class MySerObj implements Serializable {
	static final long serialVersionUID = -1;
	private List myList;
	public MySerObj(){
		myList = new ArrayList();
	}
}

We meet the first rule but violate the second.

We could simply say, hey, it's a special case and just declare the type as its implementation, no harm done.

private ArrayList myList = new ArrayList();

But, what about when the List needs to come from an external source?


public void setData(List list){
	this.myList = list; // compiler error (expecting an ArrayList)
}

To prevent the compiler error, the code would need to be changed to:


public void setData(ArrayList list){
	this.myList = list; 
}

This restricts users of the class to to specific implementations, which is a bad thing. So, how about a case for a protective copy? It's generally considered a good idea anyway (especially if you've read Effective Java , which I know you have).

public void setData(List list){
	this.myList = new ArrayList(list);
}

There may be a performance hit but, it also comes with the benefit of preventing modification of the original List which still conforms with the best practice of avoiding side effects. So, even though it's more code, it's still not necessarily a bad thing. At any rate, the code now looks like:

public class MySerObj implements Serializable {
	static final long serialVersionUID = -1;
	
	private ArrayList myList; // List is not Serializable
	
	public MySerObj(){
		myList = new ArrayList();
	}
	public void setData(List list){
		this.myList = new ArrayList(list);
	}
	...
}

Discuss

I just added the comment to let maintainers know that the implementation is specified on purpose. I know, it's not a perfect solution but, feel free to comment.



Sponsors:

About willCode4Beer