Saturday, 22 November 2008

Item 5: Avoid creating unnecessary objects

So this item could also be called "reuse objects as much as possible". ;-)
Joshua gives several advices how to avoid creating unnecessary objects.

1. read and know the language (spec). (or reuse immutable objects)

I also see this statement
String s = new String("i do not know the language really well"); // to not do this
too often. As Strings are immutable object in the Java Language the statment above is nonsense and creates unnecessary objects. (even worse if it is used in a loop). So: read and know the language and know about immutable and hence reusable objects


2. classes should offer a "static factory method" (seem Item 1)

As a hint in their API to reuse immutable object, their should use Item 1 e.g. a classical example is
Boolean.valueOf(String) // cheap: reuse object
instead of
Boolean(String)  // expensive: create new object
Also note that the javadoc of the latter version mentions, that using this ctor is expensive and the "static factory method" valueOf is preferred (and using this in eclipse you get the corresponding help immediately)


3. reuse mutable objects if you know they won't be modified

Now I do not agree 100% with the _phrasing_ of this statement, because if they are really immutable, why not make them final and immutable directly ? (most of the time this works) Also how do you know that they will not be modified. What about the user and maintainer of your code ?

However the example with Date and Calendar clarifies the intend and the solution: Do not compute the values again each time you use them in a function if they do not change. Instead make them "static final" and put the computation of them into a "static { }" Block. Now instead of n computations you have now one at class initialization time. If the method is never invoked you have a little overhead, initalizing the "static final" members, but that could be eliminated with Item 71 "lazy initializing fields". However Item 71 should really only be used for very large and expensive objects as it has other drawbacks and only pays off in a few cases.


4. be aware that autoboxing (new since Java 1.5) can create unnecessary objects

e.g. a small typo (using Long instead of long) now can trigger autoboxing and unboxing. So: prefer primitives to boxed primitives (the pre 1.5 rule was also prefer primitive to their Object counterparts) and: watch out for unintentional autoboxing (e.g. the classical typoe Long instead of long).

FYI: is think this is a good thing to know about: there is currently no findbugs rule for this but you can turn on a warning in eclipse "Boxing and unboxing conversions" ;-) There are other usefull warning in that eclipse java compiler setting for coding errors...


General Points to be aware of:

There is always a trade of between clarity, simplicity or power of a programm and efficiency or performance optimization. It is not to say that efficient programs could be not simplistic (no no ;-).

Also modern JVM implementaions do their best to optimize object creation and reclamation.However you should watch out for unnecesaary objects.

I use also often a profiler to find unnecessary objects. This is not an adviced from the book, but in my experience I found a lot of Items 5 in current code bases but using a profiler and tracking down those places.

Now a more general question is: what IS an "unnecessary" object, (if you want to start a discussion ;-) because there are counter-examples where we created additional objects (maybe they are unnecessary ?) intentionally.

Examples are:
  • pooled objects in EJB container or any other container infrastructre where you do not manage the object lifecycle on your own
  • datastructures where you have some additional reserve of objects to perform efficiently in the long term e.g. in HashMap(int initialCapacity, float loadFactor) you can have a loadFactor which the corresponding javadoc talks about.
  • if you look at optimizing your disk e.g. under windows you also need additional ressources (typically 1/3 of the disk) to run the diskoptimizer in forseeable time (but that is another story).
On the other hand there is the corresponding Item 39 "Make defensive copies when needed" which is linked to this Item 5. As there is e.g. no const ref passing like in C++ you sometimes have to make defensive copies when passing parameters to functions in java. So from a security and bug finding point it is more advisable to follow Item 39 and create a few more objects. ;-). However it is important to keep an eye on Item 5 and avoid the (usually) trivial cases where really unnecessary objects are created and thrown away immediately.

No comments: