y
The I/O method
readLine
( ) (e.g. in java.io.BufferedReader) will create a new String.
y
String concatenation (e.g.: “The value is: “ + value) will generally result in creation of a
StringBuffer, a String, and a character array.
y
Putting primitive values (like
int
or
long
) into a collection (like
List
or
Map
) requires wrapping it
in a new object (e.g. Java.lang.Integer). This is usually obvious in the code, but Java 5.0
introduced the concept of
autoboxing
which will perform this wrapping automatically, hiding the
object creation from the programmer.
Some objects, like StringBuffer, provide a way to reset the object to its initial state, which can be
useful for avoiding object creation, especially inside loops. For StringBuffer, this can be done by
calling
setLength(0)
.
y
Minimize synchronized methods
Synchronized methods/blocks can have significantly more overhead than non-synchronized code.
This includes some overhead in acquiring locks, flushing caches to correctly implement the Java
memory model, and contention on locks when multiple threads are trying to hold the same lock at the
same time. From a performance standpoint, it is best if synchronized code can be avoided. However,
it is important to remember that improperly synchronized code can cause functional or data-integrity
issues; some of these issues may be difficult to debug since they may only occur under heavy load.
As a result, it is important to ensure that changes to synchronization are “safe”. In many cases,
removing synchronization from code may require design changes in the application.
Some common synchronization patterns are easily illustrated with Java’s built-in String classes. Most
other Java classes (including user-written classes) will follow one of these patterns. Each has
different performance characteristics.
y
java.lang.String is an
immutable
object – once constructed, it cannot be changed. As a result, it is
inherently thread-safe and does not require synchronization. However, since Strings cannot be
modified, operations which require a modified String (like
String.substring()
) will have to create
a new String, resulting in more object creation.
y
java.lang.StringBuffer is a mutable object which can change after it is constructed. In order to
make it thread-safe, nearly all methods in the class (including some which do not modify the
StringBuffer) are synchronized.
y
java.lang.StringBuilder (introduced in Java 5.0) is an unsynchronized version of StringBuffer.
Because its methods are not synchronized, this class is not thread-safe, so StringBuilder instances
can not be shared between threads without external synchronization.
Dealing with synchronization correctly requires a good understanding of Java and your application,
so be careful about applying this tip.
y
Use exceptions only for “exceptional” conditions
The “try” block of an exception handler carries little overhead. However, there is significant
overhead when an exception is actually thrown and caught. Therefore, you should use exceptions
only for “exceptional” conditions; that is, for conditions that are not likely to happen during normal
execution. For example, consider the following procedure:
public void badPrintArray (int arr[]) {
IBM i 6.1 Performance Capabilities Reference - January/April/October 2008
©
Copyright IBM Corp. 2008
Chapter 7 - Java Performance
138