Sunday, 18 October 2009

Item 57 - Use Exceptions only for exceptional conditions

Using exceptions only for exceptional conditions is something we can all agree with. However, this item should have been named "Don't use exceptions for control flow and how to decided between state-testing method and distinguishing return value". Bloch gives an example of how exceptions can be used for ordinary control flow, two alternatives in state-testing method and distinguishing return value and how to choose between them. I was rather hoping for some discussion of what exception conditions are, not just a brief discussion of what they are not.

Sunday, 11 October 2009

Java Dependency Management with Ivy Part I – The Basics

Along with the rich enterprise libraries that come as part of the language, one of the biggest advantages of Java is the vast number of third party libraries available. For example if you are writing an enterprise web application, GWT, Spring and Hibernate provide a framework with a huge amount of pre-existing functionality.

The size and number of dependencies grows as your application grows. GWT and Spring alone, without their dependencies, are more than 7MB. The ideal place to put dependencies is in a source control repository as part of your project so that when you or your continuous integration server check out the project for the first time all the dependencies are there. Then you don't have to go and get them and store them locally in a location that is agreed by the entire development team.

Storing the dependencies for a single project in a source control repository isn't too bad, provided there is plenty of room on the source control server.. However, if you have more than one project using the same or similar sets of dependencies the amount of space taken up in the source control repository starts to get a bit ridiculous. And then when a new version of a library comes out and you upgrade, even more space is wasted as the differences between binary jars cannot be detected, so the entire jar must be replaced.

Read more

Item 55: Optimize Judiciously

Bloch gets this item so right! He includes some famous quotes about optimisation and of course the most well known one:

We follow two rules in the matter of optimisation:
Rule 1: Don't do it.
Rule 2: (or experts only). Don't do it yet.

But Bloch doesn't leave it there. He goes on to summarise the rules with "measure performance before and after each optimization attempt." We all know this, but how many of us actually do it?

Actually I've seen these rules put to bad use and Bloch covers that too when he points out that you should still be thinking about performance issues when writing code. The example I've seen is someone retrieving a lookup table from a database for each iteration through a dataset, rather than reading it once and caching it. At least that optimisation was straight forward.

The new information that surprised me a little was that it appear to be accepted that Java does not have a strong performance model. We all know Java is traditionally slow, but i must admit I thought performance had been greatly improved in recent years. Of course the “semantic gap” between what the programmer writes and what the CPU executes is far greater than in traditional programming language.

I almost didn't need to write a summary as the final paragraph of the item summarises it so well.

Item 49: Prefer primitive types to boxed primitives

This is the first item, certainly that I have reviewed, where I feel Bloch has it spot on. There's no arguing with this one!

Bloch points out that Java has a number of primitive types such as int, double and boolean and each of these types has a corresponding reference type: Integer, Double and Boolean. These are the boxed primitives. Auto-boxing and auto-unboxing was introduced into the language in 1.5, so the Java programmer must now be more mindful of their use.

There are three main differences between primitive types and boxed primitives:

  • Primitives have only their values, whereas boxed primitives have identities distinct form their values

  • Primitive types cannot be null, but boxed primitives can

  • Primitive types are more space and time efficient than boxed-primitives

Care must be taken with using the == operator with boxed primitives as, with any other reference type, it compares identity and you almost certainly want to be comparing value. If a boxed primitive is compared to a primitive with the == operator, the primitive type is boxed and the identities compared, so care must also be taken here.

The process of boxing and unboxing, especially in a loop can serious impede performance.

Basically, boxes primitives should be avoided unless primitive types cannot be used, such as in collections or as parameterised types.