Topics within this section include:

Final Strings

Non-final static Strings are faster to access than final static Strings. This is a bit counter-intuitive and does not apply to any other data type (in fact the opposite is true for int, long, etc).

static final string myString =  "foo "

... is like a C++

#define myString  "foo "

Literal strings are confined using a hashtable so there will only be one copy of "foo " in memory. For a non-final, the VM does the hashtable lookup only once when it initializes myString. For a final string, the compiler eliminates myString and replaces it with "foo " in the bytecode, so the VM has to do a hashtable lookup each time you reference myString.

The one advantage of the static final is that it saves 4 bytes since no storage is allocated for myString.

You also need to take into account the life of the process when using just the static. In the case of the browser, for example, if a lot of the Strings in the browser were static; and not final static, the memory would just be hanging around the handheld even if the browser was never really used because the browser is always running.

To summarize, when speed is important use:

static String FOO =  "foo ";

When memory efficiency is important, use:

static final String BAR =  "bar ";

Also, if a String constant is non-final, a comment should be provided to indicate that the String is non-final for performance reasons and a statement of the performance reason.

Inner classes

Whenever possible, inner classes should be declared as static. The only time you should use a non- static inner class is when you need access to the outer class's instance data from within methods of the inner class. If you are just using an inner class for name scoping, make it static.

There are costs involved in using a non-static inner class. They contain an implicit pointer to the outer class's this , which costs in terms of object size and code generated for constructor calls, and outer class references.

The following code:

	class outer {
int i;
class inner {
inner() {}
int foo() { return i; }
}
}

... is really just a short form for this:

class outer {
int i;
}

class outer$inner {
private outer outer$this;
outer$inner( outer o ) { outer$this = o; }
int foo() { return outer$this.i; }
}

However, this code:

 class outer {   static class inner {} } 

... really just scopes the name of the inner class, like this:

class outer {
}

class outer$inner {
}

Inner classes should also avoid being private. Use of the private access specifier means that javac has to generate extra code to access the default constructor. Use the default package access, or public, if that is appropriate.

Stack versus Member object accesses

When accessing a data member three or more times, it is cheaper to cache the field value in a local variable.

Conditionals are boolean

Instead of this:

if( something_that_evaluates_to_true ) {
return true;
} else {
return false;
}

... use:

return( something_that_evaulates_to_true );

In addition to being easier to read, the resultant class file is 6 bytes shorter.

Saving objects for large tree-like data structures

For large tree-structured data structures like hierarchies or folder structures, object ordinal usage can be reduced by the following idiom:
class Tree {
Tree left;
Tree right;
int value;
};

Convert 1000 objects with three members to three arrays:

short left[1000];
short right[1000];
int value[1000];

... and use integer values to refer to tree nodes within the array.

Remove unused code

During development, there are often several attempts at creating a software solution to a problem. As the code transforms from the first cut to the final result, leftover pieces of code accumulate. These are classes and methods that are never used. Neither javac nor RIM ’s compiler removes these unused pieces of code for you. Once a body of code is in working form, it should be inspected for these leftover pieces and they should be removed manually.

This cleanup reduces code size on the handheld and makes the code easier to understand and maintain.

Use static final boolean for debug code

When tracking down a bug, it is often necessary to instrument the code. After the bug has been found and fixed, there is still the extra debug code. Simple println() calls should most likely be removed, or at least commented out. Sometimes finding the bug required adding some more significant code. Often this code took some effort and would come in handy when another bug appears. Thus it is reasonable to leave the debug methods in the code, so that they don't have to be recreated the next time. On the other hand, we don't want to pay the price of the code size when we aren't debugging. Javac supports the following idiom:

class fubar {
public static final boolean DEBUG = false;

private figureOutBug() {
if( DEBUG ) {
// do something interesting
}
}

public usefulMethod() {
...
if( DEBUG )
figureOutBug();
...
}
}

When this code is compiled, and DEBUG is false, the portions that can never be executed are omitted by javac. Furthermore, when the compiler detects that the private figureOutBug method is never called and has no code, it will remove the method entirely.

If another bug appears, the static final DEBUG boolean can be changed to true and all the debug code will be reactivated.

Use StringBuffer wisely

Javac tries to be helpful. It supports the '+' operator for Strings . This allows for code like:

int left = 1;
int right = 2;
int value = left + right;
System.out.println( "When adding " + left + " to " + right + " the result is: " + value );

What is often not apparent is that the above expression produces this code:

StringBuffer temp = new StringBuffer();
temp.append( "When adding " );
temp.append( left );
temp.append( " to " );
temp.append( right );
temp.append( " the result is: " );
temp.append( value );
System.out.println( temp.toString() );

The first form makes the code easier to read but obscures the cost associated with the code.

Note that the one time when javac does make it cheaper is this:

System.out.println(  "First line of message\n " +  "Second line of message " );

This produces this code:

System.out.println(  "First line of message\nSecond line of message ");

So, when concatenating Strings , think about whether it is necessary and then look at the arguments.

Creating garbage

String concatenation using the '+' operator is particularly good at creating stealth garbage. Under the covers the compiler generates code to create a new StringBuffer object, append some strings into it and then creates a new String object using StringBuffer.toString() . An innocent looking line like String s = s1 + s2 + s3 could create half a dozen bits of garbage. We suggest using the StringBuffer directly and then set the object to null when you’re done with it.

Use switch instead of cascading if/else

When checking a variable of primitive type against a set of values, use switch() instead of a series of if/else statements.

This code:

if( x == 1 ) {
// do something
} else if( x == 2 ) {
// do something else
} else if( x == 3 ) {
// do another thing
} else {
// do the last thing
}

Should be transformed to:

switch( x ) {
case 1:
// do something
break;
case 2:
// do something else
break;
case 3:
// do another thing
break;
default:
// do the last thing
break;
}

This lets the VM do the series of comparisons and reduces the number of times that the value of 'x' must be fetched.

The flip side is that whenever possible, use a primitive type for a range of values, rather than using a String , or some other reference type.

Use 'char' for single character Strings

It is not recommended to create a String like "a ". Use 'a' instead.

For example:

StringBuffer tmp = new StringBuffer();
tmp.append( left );
tmp.append( "+ " );
tmp.append( right );
tmp.append( "= " );
tmp.append( left+right );
System.out.println( tmp.toString() );

... should be coded as:

StringBuffer tmp = new StringBuffer();
tmp.append( left );
tmp.append( '+' );
tmp.append( right );
tmp.append( '=' );
tmp.append( left+right );
System.out.println( tmp.toString() );

This saves the time required to instantiate two extra Strings which immediately become garbage and have to be collected.

Know your libraries

Whenever you are about to write some code to do a primitive operation on a common data type, check first to see if that code already exists in a utility class.

Initialization code should be optimized for size

Since initialization code is only meant to be run once, it should favor size over speed. If there are two ways to write the init code, one that is smaller and one that is faster, pick the smaller one.

Exception code should be optimized for size

Since exception code is meant to rarely, if ever, be executed, ensure that it is as small as possible. Make sure that exception messages aren't any longer than necessary. Often the stack traceback is all that is really needed.

When defining exception classes, consider whether a hierarchy is necessary. If the calling code isn't going to distinguish which exception was thrown, only define one type. This reduces the code size cost associated with multiple exception types.