Object re-usability and mutable objects


It’s always a good practice to use existing objects rather than creating new ones, unless required. Singleton property for example provides such a feature by not exposing Object’s constructor to the user (by keeping it private), and providing a utility method (i.e. getInstance()) which does the trick.
So, re-use doesn’t need extra memory for instantiation, it just uses the same memory, its faster, and you can keep track of instances easily, since you will have less of them.
So, those Objects which can be re-used, are most probably the ones that are immutable (their instance cannot be modified, its information doesn’t change until its life), take an example of a String,

String strObject = new String(“hello, I am a String!”);

Above expression is so bad, that it should be avoided at all costs. The literal “hello, I am a String!” creates an instance on its own, new String() creates another instance on its own, and each time above expression is executed those instances get created again and again. It doesn’t care if “hello, I am a String!” is already in memory. If you loop around for 1000 times over this expression, it will prefer creating numerous instances of String. It’s better to use following expression instead. This expression provides re-use of the String besides creating single instance.

String strObject = “hello, I am a String!”;

A good way to avoid creation of duplicate objects is using Factory methods, and Static Factory methods. i.e. myObject.getXYZObject(“xyzObject”); Boolean.valueOf(String);
However, myObject and Boolean’s constructor would create just another object if used each time.
For mutable object, of whom you know would never change, you can re-use them too. An example follows

public class Person {
private final Date birthDate;
// Other fields omitted
public Person(Date birthDate) {
this.birthDate = birthDate;
}

public boolean isBabyBoomer() {
Calendar gmtCal =
Calendar.getInstance(TimeZone.getTimeZone("GMT"));
gmtCal.set(1946, Calendar.JANUARY, 1, 0, 0, 0);
Date boomStart = gmtCal.getTime();
gmtCal.set(1965, Calendar.JANUARY, 1, 0, 0, 0);
Date boomEnd = gmtCal.getTime();
return birthDate.compareTo(boomStart) >= 0 &&
birthDate.compareTo(boomEnd) < 0;
}
}

The approach used in above example should be avoided at all costs. It would just create too many objects each time isBabyBoomer() method is accessed. An improved version of the same program would keep all the instances that can be re-used as static and use them each time in isBabyBoomer() method.

class Person {
private final Date birthDate;
public Person(Date birthDate) {
this.birthDate = birthDate;
}

/**
* The starting and ending dates of the baby boom.
*/

private static final Date BOOM_START;
private static final Date BOOM_END;
static {
Calendar gmtCal = Calendar.getInstance(TimeZone.getTimeZone("GMT"));
gmtCal.set(1946, Calendar.JANUARY, 1, 0, 0, 0);
BOOM_START = gmtCal.getTime();
gmtCal.set(1965, Calendar.JANUARY, 1, 0, 0, 0);
BOOM_END = gmtCal.getTime();
}
public boolean isBabyBoomer() {
return birthDate.compareTo(BOOM_START) >= 0 &&
birthDate.compareTo(BOOM_END) < 0;
}
}

In this version of code, unnecessary instantiations of calendar are avoided, they are instantiated once when the class is used. However, if isBabyBoomer() is never used, it still creates unnecessary objects. That’s the tradeoff; it would save you a lot of time and memory if isBabyBoomer is frequently accessed.
We can even get rid of this unnecessary initialization through lazy initialization of variables the first time when this method is invoked. But, the effort is not worth it, is it?

SOURCE : Effective Java, Joshua Bloch.

Comments