Learn to use the debugger
Your favourite IDE has a powerful debugger which you can use to debug your programs. If you are new to programming, chances are that you are aware of it’s existence, but never use it.
The problem
Here is an example method, which has a problem. (It actually does nothing of value, but demonstrates the problem case). The method doSomething is called with a parameter, but the expected result is not returned.
public Box doSomething(Box foo, Box bar) {
Box temp = foo.cloneMe();
if (bar!=null) {
Box newBox = new Box(bar);
if (newBox!=null) {
temp = doSomethingElse(foo);
if (foo==null) {
temp = bar;
}
}
}
return temp;
}
Here you can see the most frequent (ab)use of System.out.println statements.
public Box doSomething(Box foo, Box bar) {
System.out.println(”1″);
Box temp = foo.cloneMe();
if (bar!=null) {
System.out.println(”2″);
Box newBox = new Box(bar);
if (newBox!=null) {
System.out.println(”3″);
temp = doSomethingElse(foo);
if (foo==null) {
System.out.println(”4″);
temp = bar;
}
}
}
return temp;
}
The developer’s intent is to trace which if-statements execute, so as to find the bug. If 1 2 3 is displayed in the console, the developer knows that foo==null evaluated to false.
An “enhancement” of this method is to add variables of interest in those System.out.println statements.
public Box doSomething(Box foo, Box bar) {
System.out.println(“1: ” + foo + ” ” + bar);
Box temp = foo.cloneMe();
if (bar!=null) {
System.out.println(“2: ” + temp);
Box newBox = new Box(bar);
if (newBox!=null) {
System.out.println(“3: ” + newBox);
temp = doSomethingElse(foo);
if (foo==null) {
System.out.println(“4: ” + temp);
temp = bar;
}
}
}
return temp;
}
This is one of the most crude ways to debug a program. Unfortunately it’s quite common between junior developers. Note that if logging needs to be performed (for monitoring or historical purposes) a proper logging framework has to be used.
Things get interesting when the developer forgets to delete those System.out.println statements. The application is deployed, in a servlet container which hosts more applications, featuring code “debugged” in this way.
It’s not rare to see catalina.out logs which look like this:
INFO: Find registry server-registry.xml at classpath resource 20 Απρ 2007 10:23:24 μμ org.apache.catalina.startup.Catalina start INFO: Server startup in 14063 ms 20 Απρ 2007 10:23:24 μμ org.apache.catalina.core.StandardContext reload INFO: Reloading this Context has started 1 2 is null 3 copying file pic_01.jpg->temp/pic_01.jpg copying file pic_02.jpg->temp/pic_02.jpg copying file pic_03.jpg->temp/pic_03.jpg copying file pic_06.jpg->temp/pic_06.jpg 1 2 is null 3 true 4 5 6 ** BEGIN NESTED EXCEPTION ** java.net.ConnectException MESSAGE: Connection refused: connect STACKTRACE: java.net.ConnectException: Connection refused: connect at java.net.PlainSocketImpl.socketConnect(Native Method) at java.net.PlainSocketImpl.doConnect(PlainSocketImpl.java:333) ... is null false java.lang.NullPointerException BoxExample$Box@126b249 1 2 is null 3 resultset was null 1 resultset was null ...
The solution
Learn to use your debugger. All you have to do is go to the line you want debugging to start, set a breakpoint (CTRL+F8 in Netbeans) and start the debug process. You will either debug the whole application (F5) or that single file/unit test (CTRL+SHIFT+F5).
You can set watches, see the stacktrace and examine the contents of all the local variables at any time in the program execution. You get orders of magnitude more power, in less time; for free!
Try it out. When you get used to it, you’ll never look back.