| < Free Open Study > |
|
Programmers who write poor code can wreck the performance and scalability of even the best-designed system. In this section, we will cover good practices that will help you to write efficient servlet code (although the following tips are equally relevant to any Java code).
In this first section we'll consider how we should approach coding classes.
Deep inheritance hierarchies impose extra burden on the VM (virtual machine) for executing all of the superclass constructors. To avoid this use shallow inheritance hierarchies. One of the basic lessons of object-oriented programming is that object composition is preferred to class inheritance.
The classes from the collection framework like ArrayList, HashMap, and so on are faster than the Vector class. This is because all of the methods on the Vector class are synchronized to make them thread safe whereas the classes belonging to the Collections framework are not thread safe.
Using reflection extensively in your code can degrade the performance of your system. However, JDK 1.4 offers considerable performance improvement when using reflection.
Avoid making your servlets implement the SingleThreadModel interface. It is always better to write thread-safe code.
Stateless session beans are always more efficient than their stateful counterparts. Use stateful session beans only if you want the state to be maintained between public method calls.
This section contains some guidance for how you should approach the use of variables and operators in your code.
Local variables are faster to access than instance variables, because they are stored in the stack instead of the heap.
It is always faster to declare variables outside a loop even if they are used only inside the loops, because we then we don't instantiate an object with each new loop. For example:
for(int j = 0; j < 10; j++) { MyObject myObject = new MyObject(j); myObject.someMethod(); }
The above code may be rewritten as shown below to improve performance.
MyObject myObject; for(int j = 0; j < 10; j++) { myObject = new MyObject(j); myObject.someMethod(); }
Defining instance or class variables that are only used for storing constant values can improve performance.
Character arrays are faster than strings and string buffers.
String objects in Java are immutable. This means that whenever you invoke a method on a String variable that amends its contents, the original contents of the String is left unaltered and a new string that contains the result of invoking the method on the original content is created. If your servlet performs content generation and involves quite a lot of string concatenation it is better to use a StringBuffer rather than the + operator. For example:
String myString = ""; for(int i = 0; i < 1000; i++) { myString += "test"; } System.out.println(myString);
The above code snippet will perform lot better if written as shown below:
StringBuffer myString = new StringBuffer(); for(int i = 0; i < 1000; i++) { myString.append("test"); } System.out.println(myString);
Compound operators generate less byte code and are hence faster than normal operators.
int j = 10; j = j + 20;
The above code may be rewritten as:
int j = 10; j += 20;
In this section we'll discuss a few hints for good coding practice related to method design.
Only lock (synchronize) the required bits of code, to avoid lock contention that negatively impacts upon performance in a multi-threaded environment. For instance:
public synchronized void myMethod() { //Thread safe code; //Thread unsafe code; }
The above method may be rewritten as
public void myMethod() { //Thread safe code; synchronized(this) { //Thread unsafe code; } }
Declaring a method as final, static or public will help the Java compiler optimize the code during compilation without worrying about late binding.
Using the arrayCopy() method defined in the java.lang.System class is much faster than looping through the source array and copying the items. This is because this method is defined natively.
Use the notify() method instead of notifyAll() for notifying the threads waiting on monitor locks, as it is faster.
The charAt() function is faster than the startsWith() method in the String class, if you are comparing only one character. In other words, the following code:
System.out.println("Meeraj".startsWith("M"));
is slower than:
System.out.println("Meeraj".charAt(0) == 'M');
The way that you enable data access within your application often has a major effect on your application's performance. We will discuss this in more depth later in the chapter. First, here are some coding tips related to database access.
When you select columns from a database table using JDBC, select only those columns you need. This will restrict the amount of data transferred between the data server and your application, improving performance.
When retrieving data from ResultSet objects, use the appropriate version of the get method corresponding to the expected type of the column, instead of using generic getObject() and getString() calls. This will avoid overheads associated with unnecessary type conversions.
PreparedStatements are considerably faster than normal statements in JDBC, if the driver supports pre-compilation of PreparedStatements.
Here are some other useful rules-of-thumb for when you are coding.
Optimize your code during compilation using the -O option. However, you should note that this may hinder byte code debugging and increase class size.
Make your transactions as short as possible. This will release locks on objects more quickly, thereby reducing lock contention.
Use the -Xmx and -Xms options with the JVM to set the maximum and initial amount of heap as required.
Use asynchronous logging to improve performance. This means sending a log message to an in-memory buffer like a JMS destination, which is later written to the disk by a different thread.
To speed up serialization, declare the fields that need not be serialized, using the transient modifier.
Use externalization to create faster custom serialization algorithms.
JDK 1.4 provides options for non-blocking I/O that can improve scalability and performance.
Streams that deal with eight bit data are faster than readers and writers that use Unicode format. Use readers and writers only if you need internationalization.
Cloning is a very effective way of creating a huge number of similar objects, rather than using the new operator.
| < Free Open Study > |
|