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
Post a Comment