Back home.
Write clean, simple, elegant code.
Corollary. If your code is ugly, it is probably wrong. You need to rethink your approach.
Some programmers, especially those new to object orientation, think that you should create an object for everything. This is wasteful.
Remember the purpose of an object: to hold data over time, and possibly associate behavior with that data. If you just need a place to hold some code, and are not concerned about overriding it, or providing different versions of it, put it in a static method and call it statically. There is no need to create an object just to call a method on it. If you can, especially avoid creating an object, calling one method on it, then immediately discarding it.
Object creation takes time and heap space. Subsequent garbage collection also takes time. Creating objects unnecessarily wastes both space and time.
Where it makes sense, instead of
new MyClass().myInstanceMethod();
write
MyClass.myStaticMethod();
This sounds like it is going to contradict the previous advice.
It makes testing easier if you express behavior in interfaces rather than in static methods. This applies to behavior that you want to change, say to a mock or dummy version, for testing. If you use static methods in a utility class, you have to modify the code that calls them to replace them with test versions. If you describe the behavior by an interface, you can put the real version in one class and the test version in another class, then switch between them as you wish using configuration files.
You can often start with a test program, and then transform it step by step to become the real program. Each step of the transformation shows you more plainly what the real program should be.
Test conditions in if, while, and for statements are already boolean. There is no need to do comparisons to true and false. Using them is a holdover from C.
Instead of
if (flag == true)
{
...
}
write
if (flag)
{
...
}
Instead of
if (flag == false)
{
...
}
write
if (!flag)
{
...
}
Always put braces around then, else, while, and for blocks, even if the block is a single statement. This prevents unintentional bugs if you add code to the blocks later.
Instead of
if (x != null) process(x);
write
if (x != null)
{
process(x);
}
This avoids errors like
if (x != null)
System.out.println("Processing");
process(x); // Oops! Now the processing occurs even if x is null!
Think of variables as names for values rather than places to store values. Many variables never change once they are set. Make all variables final unless you intend to change them. It is a good discipline to make all method parameters final, period. This accomplishes several purposes:
This advice applies only to classes. Do not make method parameters parameters in interfaces final. There is no need.
If we think of variables primarily as names for values rather than as storage locations, we realize that not every value needs a name. This is because many values are created and used only once in the context that they are created. For example, a value may be merely passed to a method or returned from a method, or used as the target of a method call. The general idea is that you do not need to store a value in a variable unless you need to refer to it more than once in the context in which it is created. This simplifies the generated code and the virtual machine's job of register allocation.
Instead of
public int getIntProperty(final String key)
{
final String stringValue = Syststem.getProperty(key);
final int intValue = Integer.parseInt(stringValue);
return intValue;
}
write
public int getIntProperty(final String key)
{
return Integer.parseInt(Syststem.getProperty(key));
}
There are exceptions to this. Somtimes, the code to create a variable, though just a series of method calls, is long and complex enough that you can improve readability by storing an intermediate result in a variable, then using it to calculate the final result.
There is no need to declare method parameters in interfaces final.
There is no need to declare variables in interfaces public, static, or final, since they already are.
There is no need to declare methods in interfaces public, since they already are.
When writing array types, put the brackets after the type name rather than after the variable name as in C. This keeps the type name together and allows the reader to tell more quickly that it is an array. For "multidimensional" arrays, put all the pairs of brackets after the type name.
Instead of
String strings[]; int[] values[]; // or int values[][];
write
String[] strings; int[][] values;
When writing array initializers, put a comma after the last value as well as all the others. This is legal and makes it easier to add more values later without forgetting the comma and getting compile errors. Of course, many development environments that pre-parse make the error obvious immediately.
Instead of
int[] values = { 3, 6, 9 };
write
int[] values = { 3, 6, 9, };
Try very hard to avoid writing tests that you know in advance will be true exactly once and false the rest of the time, or vice versa, and you know when the unique case will occur. A common example is some condition that will be true the first (or last) iteration through a loop and false the rest of the iterations. Restructure the code to avoid the test and the extra time it takes.
Instead of (admittedly contrived):
// Initialize first element of array to 1, other elements to 2.
int[] values = new int[100];
for (int ix = 0; ix < values.length; ix++)
{
// This test is true exactly once, on the first iteration.
if (ix == 0)
{
// This code is run exactly once, on the first iteration.
values[ix] = 1;
}
else
{
// This code is run on every iteration except the first.
values[ix] = 2;
}
}
write
// Initialize first element of array to 1, other elements to 2.
int[] values = new int[100];
values[0] = 1;
for (int ix = 1; ix < values.length; ix++)
{
values[ix] = 2;
}
or even better, in this case:
import java.util.Arrays; // ... // Initialize first element of array to 1, other elements to 2. int[] values = new int[100]; values[0] = 1; Arrays.fill(values, 1, values.length, 2);
Say you are constructing an object, and certain arguments to the constructor must not be null because they would cause a null pointer exception when used later by the object's methods. Validate the arguments and throw an IllegalArgumentException immediately from the constructor. Probably you created the null value in the chain of calls that led up to the constructor call. It will be easier to determine the true source of the problem by examining a stack trace here than by trying to follow a stack trace leading to the method that throws a NullPointerException later on, when the source of the null value may not be at all evident.
Test code is sometimes the most interesting code that you write, since you are trying to simulate the real pieces that you do not want included in your test.
You have code that is printing something out. What is printed is not what you expected. Check your printing code. It may be that what you are printing is correct, but you are printing it incorrectly. You may be printing the wrong part of it, or printing it through a method that you did not expect. This can happen when you use the visitor pattern and your code is compiled in a strange order.
When you are writing a subclass of a class that defines a method, you should almost never write an overridden version of the method that just calls its superclass method.
void foo()
{
super.foo();
}
This is unnecessary, and even wasteful. The class you are writing will inherit the method from its superclass anyway. Writing a "trivial override" like this just wastes space by storing the unnecessary method, and time by adding an extra unnecessary call.
Some development tools may automatically generate methods like this. Check for them and remove them.
There is only one case when you would want to write such a method. That is when you need to increase the visibility of the superclass method. For example, say you are subclassing a class that someone else wrote. You may want to make a protected or package-private (why not private?) method public so that other classes can use it.
public class A
{
protected void foo()
{
// ...
}
}
public class B extends A
{
public void foo()
{
super.foo();
}
}
For example, the class java.util.Observable has protected methods clearChanged() and setChanged(). You might want a subclass that makes them public.
Page Information
|
Wiki Information |
Recent PBwiki Blog Posts |