The Source for Java Technology Collaboration
User: Password:



Tom Ball

Tom Ball's Blog

Exceptional Debugging

Posted by tball on April 04, 2005 at 03:36 PM | Comments (9)

Exceptions (and their stacktraces) are one of the features that first attracted me to Java back in early 1995; C++ obviously had exceptions, but I never worked with any C++ projects that used them as effectively as the Java core classes did. I find well-designed exceptions to be a significant productivity booster.

My first project on the JDK team was developing the debugger API, and I think it was the first debugger where you could set a breakpoint that tripped whenever a specified exception type was created (please correct me if you know of earlier systems). The justification for exception breakpoints was simple: exceptions (should) indicate abnormal control flow in a program, and since we spend most of our time in debuggers figuring out why our programs are acting abnormally, there should be an easy way to halt whenever the program is indicating something worth investigating.

But few engineers I've met use this feature, and it puzzles me a little. Most recently, I filed a NullPointerException problem which didn't log a stacktrace, and the assigned engineer first added logging code so he could get a stacktrace to see where the problem was, which he then spent a lot of time reading various source files to determine what could have caused it. If he had instead set an NullPointerException breakpoint, the debugger would have stopped at the offending statement with all of its local variable and stack information immediately available. This is much, much faster than running until a stacktrace prints, editing the code to add debug statements if the cause isn't obvious, and looping until the problem is figured out. Isn't impatience supposed to be one of the attributes of a good programmer?
Exception breakpoints can be useful even when you aren't debugging exception failures, too. In NetBeans, I always have breakpoints set for NullPointerException and AssertionError (running with the -ea flag), to catch these conditions as soon as they rear their ugly heads.

I have heard complaints that exception breakpoints are "too noisy" because they can trip in places you don't expect. I think this indicates a couple of potential design flaws:
  • Overly general exceptions: although you don't need a separate type for all possible exception cases, it is often very useful to do more than "throw new InternalError()" when a problem arises. The java.io package derives FileNotFoundException and EOFException from IOException, since for many apps these are much more common recoverable error conditions than, say, a SyncFailedException. A custom exception is a great documentation aid if you have a public API, and exception classes are simple to create and maintain.

  • Using exceptions for flow control: as Josh Bloch argued in Effective Java, "Use exceptions only for exceptional conditions" (item 39). In the Solaris JDK a few years back, for example, system font files were discovered by trying to open all possible font names and catching all the FileNotFoundExceptions. This was much slower and more memory intensive than using File.exists(), due to all the exception object creation and collection. If your program is querying a class by poking it and testing for exceptions, add a method to that class to get the information directly.
Another complaint is that exception breakpoints catch exceptions in OPC ("other people's code", the source of all developers' woes :-). For example, Swing uses NullPointerException for flow-control in a couple of places, so I filed bugs when they tripped (should be fixed in Mustang) and now just hit continue. I strongly recommend filing such bugs as you find them (along with a recommended patch), so as to eliminate these nits and improve the Java platform as a whole. After all, the more successful it is, the more successful we Java developers will be.

Bookmark blog post: del.icio.us del.icio.us Digg Digg DZone DZone Furl Furl Reddit Reddit
Comments
Comments are listed in date ascending order (oldest first) | Post Comment

  • Hi There,

    I'm one of those guys who was looking for Breakpoint on Exceptions (since I came from using WinICE/SoftICE BPINT, etc-- for that matter, Visual Studio/Windows SDK had something equivalent called DebugBreak()).

    When I use Eclipse to set breakpoint on java.lang.Exception, I hit a lot of exceptions in the java RTL. I wish IDEs had a way of saying, only break in my code and not in someone else's code(including library). I guess, for that happen, the JVMTI interface should help the IDEs.

    Also, it would be great if IDEs had the feature like Visual Studio/Windows SDK' DebugBreak(http://msdn.microsoft.com/library/default.asp?url=/library/en-us/debug/base/debugbreak.asp) where if the code hits an exception, the RTL will launch a DIALOG enabling the foreground user to launch an IDE to debug the application. Such a feature will be really cool for Swing applications and command-line applications. I'm not sure how useful it will be for server based applications -- perhaps an IRC message with a link that will launch a remote-debug session ?

    BR,
    ~A

    Posted by: anjanb2 on April 04, 2005 at 06:44 PM

  • anjanb2, some good Java debuggers do allow you to 'filter' out classes from packages you didn't write. For example, IntelliJ's debugger allows you to set exception breakpoints, yet ignore the breakpoint if it gets trapped in a class you've excluded.

    tball, how about Class.forName() as a prime example of control-flow-via-exception? We need the equivalent of file.exists() in that context.

    Posted by: dtbullock on April 05, 2005 at 01:40 AM

  • >I wish IDEs had a way of saying, only break in my code and not in someone
    >elses code(including library).

    With Eclipse, you could use the filters for Breakpoints; on an Exception Breakpoint open its Filter settings (available from the popup menu on the Exception Breakpoint); here you can restrict the exceptions to a particular thread and to individual classes and packages.

    Posted by: murphee on April 05, 2005 at 04:55 AM

  • Thanks for pointing out this feature. I was looking for this for a long time.

    Posted by: mnuhoglu on April 05, 2005 at 07:21 AM

  • NetBeans supports conditions on breakpoints today, but the filtering options described above sound like good enhancements.

    A Class.classExists() method would be a useful enhancement to avoid using Class.forName(), but you can write that in your own code:

    public boolean classExists(String name) {
    return getClass().getResourceAsStream(name) != null;
    }

    Class.getResource() is more efficient (a URL is returned instead of the file being loaded into an InputStream), but some SecurityManagers (like applets) will not allow this operation since the URL might disclose network configuration details.

    Posted by: tball on April 05, 2005 at 09:05 AM

  • Really good suggestion! I added this NullPointerExcpetion breakpoint in my WSAD, I just got so many exceptions in WSLauncher class. I have disable it to allow the server up.

    Posted by: libo_tsinghua on April 05, 2005 at 09:13 AM

  • Maybe it's time to switch application servers. ;-)

    Posted by: tball on April 05, 2005 at 09:35 AM


  • public boolean classExists(String name) {
    return getClass().getResourceAsStream(name) != null;
    }


    Should be

    public boolean classExists(String name) {
    String resource = name.replace('.','/') + ".class";
    return getClass().getClassLoader().getResource(resource) != null;
    }


    Notes:

    appended ".class", because we are looking for a *.class resource.
    used ClassLoader.getResource() because Class.getResource() can succeed for unqualified names in the same package which then fail when Class.forName() is called.
    used getResource() not getResourceAsStream() to avoid the overhead of opening the resource, and avoid potential problems with not closing it afterwards.

    Posted by: brucechapman on April 05, 2005 at 06:12 PM

  • Thanks for the code improvement -- this will teach me to pull examples from working code (such as how java.beans.Beans does it) instead of memory!

    Posted by: tball on April 06, 2005 at 07:36 AM





Powered by
Movable Type 3.01D
 Feed java.net RSS Feeds