Wednesday, September 11, 2013

Coding Zen: Debugging by understanding

The wise programmer does not seek to find the solution, but to understand the problem.
It's been two months today, since I initialized Blog codeCrave = new Blog();, and since then I've encountered a number of interesting problems with my code. Many of them I've omitted posting about, because of the lovely tool known as Stack Exchange, and its more-commonly-used Stack Overflow. This lovely site has (very appropriately) datified the many problems one might encounter when working on making a computer or web application of any kind.

Shamelessly borrowed from Java EE Support Patterns blog
But in many ways, it serves to weaken the mind. By delegating our problem-solving skills to the crowd-sourced Stack*, we risk denying ourselves adequate development of our own problem-solving skills.

Consider the ClassNotFoundException that is often called the "bane of Java programmers," so much so that there's an entire web service dedicated to helping you debug a ClassNotFoundException. Does that seem excessive?

It's not. Because this problem can be a doozie.

Mindful of the above heuristic, I'm going to walk through the ClassNotFoundException: what it is, what can cause it, and how to solve it. I will go through my particular solution.

What is a ClassNotFoundException?

This is one particular exception thrown in Java when the lazy JVM first tries to load a class (which is the first time it's called in your code, hence the 'lazy'). If the JVM cannot find your class, this exception will be thrown.

If you want to see some example code, you can check out commit dc854eb on my Acamedia project, on GitHub (which I'll expand upon a bit later). Alternatively, read this entry from Java EE Support Patterns.

Causes of this exception

ClassNotFoundException is thrown when an application tries to load in a class through its string name using one of three methods, from two different classes in the java.lang package:
Basically, Java either could not find or could not load some particular class. If your IDE doesn't give you any syntactic errors (such as "a class with the name 'Cavinet' does not exist," if you're following my code from above), it's probably happening at runtime, through the JVM.

In most cases, this exception is reportedly caused by use of external APIs, or an improper inclusion of the file into your project. It can even be a missing CLASSPATH environment variable, but this cause seems to be much less common as it's bad practice to use an environment variable (lack of portability).

Understanding the problem; creating a solution

It's easy to search Stack Overflow for the many different cases, and try each one to see if your case fits, and you successfully debug. But this is a very surface-level strategy, and won't prevent future throws because you will continue to make whatever mistake you made.

Instead, seek to understand the problem fully: this exception is thrown when the JVM cannot find your class. It seems so obvious (ClassNotFoundException), but ask yourself this: what are all the ways the JVM could lose your class?

Without coming to understand more about the JVM, you won't know. It could be as simple as a misspelling, or a missing line in your classpath file; you could have incorrectly packaged your file. It may be something more complex, as well.

Assigned reading:

My case: a masked exception

If you're following my code, the class initialization call that's throwing the error is on line 17...
Cabinet cab = new Cabinet(homedir, "cab", out);
...of class CabinetTest. Note that CabinetTest properly imports Cabinet, and the classpath file seems to correctly include my source files in line 3. And because I'm only using the Java API, the cause is probably not from using an external API; the Java library is correctly imported.

Reading this blog post from Javarevisited, I found something that sounded suspicious:
Beware that if your static initialize block throws Exception than you may get java.lang.NoClassDefFoundError when you try to access the class which failed to load.
That sounded like it was worth checking, so I went into my Cabinet constructor and commented everything out. Lo and behold, it worked. this led me to ask "why?" and as a result I did some heavy reading on the static keyword, initialization, and how those might throw this exception.

Here's some extra reading:

No comments:

Post a Comment