Java Optimization

     My first and most major advice regarding optimization in Java is this: don't do it. That is, unless you are sure that it is really called for. In nearly any large application, 90% the memory and CPU usage are tied up by just 1% of the code. Spending your time optimizing the other 99% is wasted effort.

     So real optimization should concentrate on the optimizing the heck out of the limiting step. Before changing any code to be optimal, you need to find what is taking the most time and/or memory.

     Below I cover optimization grouped by the class or category which it applies to. Unless otherwise noted, all these steps outlined below apply to JDK 1.1.

java.lang.String

java.lang.StringBuffer

java.util.Vector

java.util.Hashtable

Object Instantiation

Methods

     Unless you live in a cave, you probably call a lot of methods in your Java code. Here are the relevant benchmarks:

static (class) methods
These are the fastest to call, taking around 220ns.
final methods
These are somewhere between static and instance methods, taking around 300ns.
instance methods
These are a little slower, taking around 550ns.
interface methods
These are surprisingly slow, taking on the order of 750ns to call.
synchronized methods
These are by far the slowest, since an object lock has to be obtained, and take around 1,500ns.

     The moral of the story is that if you can get away with it, use static final methods, and don't use interfaces. This is too bad, since most good OO design involves interfaces and for the most part, static methods are only useful in "library" classes that are just a collection on useful methods.

Loops

     Most people write their for loops like this:

for (i=0; i<n; i++)
{
  // do some stuff
}
But, since in almost every language, comparing an int to something else is almost always faster if that something else is a 0. If we re-write the loop like this:
for (i=n-1; i>=0; i--)
{
  // do some stuff
}
It looks backwards, but it's faster. This can be a problem if you need to actually count up from 0 to n, but if not, it's nice. It's even better if you roll up the decrement into something like this:
for (i=n; --i>=0;)
{
  // do some stuff
}
This way, you don't have to do the substraction at the beginning of the loop.

Array bounds checking

     As any good (or bad) C and C++ programmer knows, going off the end of an array is a Bad Thing (TM). As you may have noticed, Java does not let you get away with this kind of thing has provides an implicit bounds check, and throws an ArrayIndexOutOfBoundsException exception when you read off the end of an array. Some people have suggested that when you are setting all the values of an aray iteratively, like this:

for (i=array.length; --i>=0;)
{
  array[i] = stuff;
}

that this code could be better done like this:

try
{
  for (i=array.length; ; --i)
  {
    array[i] = stuff;
  }
}
catch (ArrayIndexOutOfBoundsException x) { ; }
thereby skipping the >= check done on each loop iteration. This can be considerably faster, but if you have short arrays, it's less optimal since throwing and catching a new Exception takes 9,500ns and doing a >= int compare takes about 250ns (on a 200MHz UltraSPARC), so the breakpoint is about 40 elements. Obviously this is no use if you're not going from some point inside the array (including either end) to one end or the other.

     Also, if all you're doing is setting values of one array to another, use System.arraycopy(Object, int, Object, int, int) since it's much, much faster than a for loop.

Local variables

     If you're going to do lots of operations with an instance variable inside a method, like this:

public class Foo
{
  private int[] array;
  ...
  public void foo()
  {
    try
    {
      for (int i=array.length; ; --i)
      {
        array[i] = i*2; // or something
      }
    }
    catch (ArrayIndexOutOfBoundsException x) { ; }
  }
}
this will run considerably faster if it's re-written like this:
public class Foo
{
  private int[] array;
  ...
  public void foo()
  {
    int myarray[] = array;
    try
    {
      for (int i=myarray.length; ; --i)
      {
        myarray[i] = i*2; // or something
      }
    }
    catch (ArrayIndexOutOfBoundsException x) { ; }
  }
}
the same goes for local references to loop index vars, etc... this is faster since the VM only has to resolve the reference outside the method once, at the start of the loop, rather than each time.