Saturday 4 June 2011

Immutable objects. Really?

One of the important characteristics of the object world is favour immutability. It's a simple and efficient way of protecting data and functionality of an object from misuse by the users for years to come. When an object is composed of Java library classes (such as java.util.Date or java.sql.Time) or other third party classes which are themselves mutable, then the immutability is broken thus there is a possibility for the change of state of the object by other objects.

The following class, RequestBatch looks pretty much like immutable given that it does not allow inheritance and provides no mutators. But it's field _requestsBatch breaks all of it.

import java.util.ArrayList;

import java.util.List;



public class RequestBuilder {



 public static void main(String[] args) {



  List<requestbatch> requestBatchList = new ArrayList<requestbatch>();

  List<String> requests = new ArrayList<String>();

  for (int reqBatchCount = 0; reqBatchCount < 5; reqBatchCount++) {

   for (int reqCount = 0; reqCount < 10; reqCount++) {

    requests.add("Request_" + reqBatchCount + "_" + reqCount);

   }

   RequestBatch requestBatch = new RequestBatch(requests);

   requestBatchList.add(requestBatch);

   requests.clear();

  }



  for (RequestBatch requestBatch : requestBatchList) {

   for (String request : requestBatch.getRequests()) {

    System.out.println(request);

   }

  }

 }

}
If we attempt to print the requests in the batches, we see no requests get printed as there were none stored. All the five batches have no requests but empty list. Though this might be obvious given that the constructor is passed with a copy of the reference value of the same List (pass-by-value) all the time, the clear() method clears the _requestBatch member of the supposed to be immutable objects without their knowledge.
So, care must be taken when creating an object composing of mutable objects. With the defensive copying of the in and out parameters, the following RequestBatch class would make it possible to create immutable objects.
import java.util.ArrayList;

import java.util.List;



public final class RequestBatch {



 private List<String> _requestBatch;



 public RequestBatch(List<String> requests) {

  _requestBatch = new ArrayList<String>(requests);

 }



 public int batchSize() {

  return _requestBatch.size();

 }



 public List<String> getRequests() {

  return Collections.unmodifiableList(_requestBatch);

 }

}

No comments:

Post a Comment