java

Java exceptions guide

This is intended as a dumping ground for all the tips on using exceptions that I accumulate over the years.

Don't swallow exceptions

Never, ever do this:

try {
  ...
} catch (IOException ioe) {
  // do nothing here
}

Always log a message, or print a stacktrace, or re-throw the exception, or throw a new exception (and wrap the caught exception).

Allow your checked exceptions to wrap other exceptions

class MyException extends Exception {
  public MyException(String message, Throwable cause) {
    super(message, cause);
  }
}

This is almost always useful. You will often find yourself catching an IOException and re-throwing it as your own exception. The main point is DON'T DISCARD THE ORIGINAL EXCEPTION. If you do, you won't see it any stack traces as the "caused by:" exception.

Don't log an exception that you are re-throwing or wrapping

This is a minor detail but it makes for much cleaner logs.

try {
  ...
} catch (IOException ioe) {
  log.error("Got an IOException", ioe); // not necessary
  throw new MyException("Had a problem contacting the server on port " + port, ioe);
}

In the above, assuming the logger is log4j or something similar, it is going to print the stacktrace for the IOException exception. Then whatever catches MyException up the stack will also log the IOException. This makes for message logging. Either log the IOException and do not wrap the IOException, or don't log it and just wrap it.

Create your own top-level exception classes

I've often found it useful to create two top-level exception classes, one that extends Exception and one that extends RuntimeException. For example, ABCCompanyException and ABCCompanyRuntimeException. Sometimes at the top-level of your application (in the main() method or the HTTP request handler, for example) you want to catch everything that hasn't been dealt with yet. It can be useful to handle "ABCCompanyException" and it's sub-classes separately from Java's "Exception" or "ABCCompanyRuntimeException" separately from Java's RuntimeException.

Don't forget to catch run-time exceptions in callback methods

Let's say you're implementing an event handler to be used in a third-party event bus framework, or implementing an "onOpen/onClose/onMessage" type interface for a web socket client. You should wrap the entire body of the method in a try...catch (Throwable t) otherwise a run-time message might be thrown somewhere, bubble up into the third-party library, and be swallowed there. Do this any time you are implementing a method that you don't actually call yourself. The same thing goes for the run() method in the Runnable class.

Using XML for Code Documentation is Just Plain Wrong

I was just looking at some C# code at work today and it had XML Documentation (like javadoc or python docstrings, only with XML). Who was the idiot that came up with that idea? It's the most insane thing I've ever seen. Let's look at the predecessors to C#'s XML documentation:

Javadoc:

/**
 * Returns an Image object that can then be painted on the screen. 
 * The url argument must specify an absolute {@link URL}. The name
 * argument is a specifier that is relative to the url argument. 
 * <p>
 * This method always returns immediately, whether or not the 
 * image exists. When this applet attempts to draw the image on
 * the screen, the data will be loaded. The graphics primitives 
 * that draw the image will incrementally paint on the screen. 
 *
 * @param  url  an absolute URL giving the base location of the image
 * @param  name the location of the image, relative to the url argument
 * @return      the image at the specified URL
 * @see         Image
 */
 public Image getImage(URL url, String name) {
	try {
	    return getImage(new URL(url, name));
	} catch (MalformedURLException e) {
	    return null;
	}
 }

Then, doxygen, which looks a lot like javadoc:

      /**
       * a normal member taking two arguments and returning an integer value.
       * @param a an integer argument.
       * @param s a constant character pointer.
       * @see Test()
       * @see ~Test()
       * @see testMeToo()
       * @see publicVar()
       * @return The test results
       */
       int testMe(int a,const char *s);

Unfortunately Genshi doesn't syntax highlight the javadoc comments. But it looks fairly readable. Let's try a python docstring example. There is no one standard. One of the documentation generators for Python, Epydoc understands plaintext, javadoc, epydoc, and reStructuredText.

Python code with epydoc style docstrings:

def x_intercept(m, b):
    """
    Return the x intercept of the line M{y=m*x+b}.  The X{x intercept}
    of a line is the point at which it crosses the x axis (M{y=0}).
 
    This function can be used in conjuction with L{z_transform} to
    find an arbitrary function's zeros.
 
    @type  m: number
    @param m: The slope of the line.
    @type  b: number
    @param b: The y intercept of the line.  The X{y intercept} of a
              line is the point at which it crosses the y axis (M{x=0}).
    @rtype:   number
    @return:  the x intercept of the line M{y=m*x+b}.
    """
    return -b/m

Python code with one example of reStructuredText docstrings (this one includes the types of the parameters but they aren't necessary):

def fox_speed(size, weight, age):
    """
    Return the maximum speed for a fox.
 
    :Parameters:
      size
        The size of the fox (in meters)
      weight : float
        The weight of the fox (in stones)
      age : int
        The age of the fox (in years)
    """
    #[...]

I couldn't find any nice examples for C# XML Documentation. The C# XML Documentation Tutorial has some examples, but conveniently, none that include all the tags that I would need to replicate the javadoc example I showed above. So I'll convert the Java example to C#:

   /// <summary>
   /// Returns an Image object that can then be painted on the screen. 
   /// The url argument must specify an absolute {@link URL}. The name
   /// argument is a specifier that is relative to the url argument. 
   /// 
   /// This method always returns immediately, whether or not the 
   /// image exists. When this applet attempts to draw the image on
   /// the screen, the data will be loaded. The graphics primitives 
   /// that draw the image will incrementally paint on the screen.</summary>
   /// 
   /// <param name="url">an absolute URL giving the base location of the image</param>
   /// <param name="name">the location of the image, relative to the url argument</param>
   /// <returns>
   /// the image at the specified URL</returns>
   /// <seealso cref="Image">
   /// Read more about the Image class</seealso>
 */
 public Image getImage(URL url, String name) {
	try {
	    return getImage(new URL(url, name));
	} catch (MalformedURLException e) {
	    return null;
	}
 }

I followed Microsoft's convention (because they know best) of putting the opening tags on a line on their own.

The javadoc sucks because you have to put a <p> (or <br />?) to make a new line which is stupid. Otherwise it's pretty readable, and same goes for doxygen. Especially the @param and @return tags. The Epydoc-style python docstrings suck. You have to specify the type using a @type tag and the return type using an @rtype tag. The reStructuredText example looks the best to me. No tags at all, except for the :Parameters: heading which should be there anyways. The C# comments are an eyesore. Even if Visual Studio had syntax highlighting for the comments it would suck. Did Microsoft look at the two major previous implementations (doxygen and javadoc) and decide that XML was a better way to document code?

I recently saw an interesting comment in scipy's source about one of scipy's guiding principles in designing the docstring standard for their codebase:

A guiding principle is that human readers of the text are given precedence over contorting docstrings so our tools produce nice output. Rather than sacrificing the readability of the docstrings, we have written pre-processors to assist tools like epydoc_ and sphinx_ in their task.

Microsoft clearly took the opposite route and decided to make code documentation readability by human readers a low priority.

Maven is Amazing

After 2 senior developers recommended maven over ant and another told me he was planning on switching to it (from ant) for his next major project, I knew I would eventually try it when I had the chance. Today I was forced to try it because building my project with ant started becoming a total nightmare. I had added a dependency to my project and now the ant script failed. Time to modify the ant script. Said dependency had some dependencies of it's own. Not only that but one of the dependencies was an internal project and did not have an ant build of it's own so no Jar. So it looked like I was going to have to write an ant build for the dependency or put a hard link to it's output class path (created by Intellij IDEA) or use IDEA's jar maker utility. All of those are crappy workarounds. I like automated one like calls like "ant deploy" that will build, test, package and deploy my app to a tomcat server. I was fed up; there has got to be a better way.

So I tried Maven and it is amazing. I just converted a bunch of projects to use maven and it is so much better than ant. It follows the "convention over configuration" and DRY (don't repeat yourself) philosophies very nicely. It just works. No need to tell Maven where your source is and where you want it to build to. Just use the standard maven directory structure. No need to tell Maven what your classpath is for unit tests or compilation. Deploying builds to a remote or local repository is easy. Running unit tests and generating reports is easy, with no extra code in the build file required.The best part is that it fetches dependencies from a server (or the local repository cache) and fetches dependencies recursively. Building projects will be so much easier now and will save so much time. No more writing ant builds and no more copies of junit or log4j all over the place. In fact, never download any jars, ever again. Another bonus: it can generate an IDEA module file or modify an existing one. I've tried this for all the projects and it works perfectly.

So Maven is awesome, and Ant, well...Ant is dead to me.

Ugly Bit-Wise Arithmetic

I just had a WTF moment today. If I ever see code like this again I swear I will go postal:

answer = new long[(size + 0x3F) >>> 6];

one simpler ways to write this would be:

answer = new long[size/64 + 1];

This is java by the way, not C.

Tags:

Anti-Aliasing in Java >=1.3

It's really simple. Just add the a few lines of code at the top of your paintComponent method:

protected void paintComponent(Graphics g) {
  super.paintComponent(g);
  Graphics2D g2d = (Graphics2D) g;
  g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
  g2d.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING, RenderingHints.VALUE_TEXT_ANTIALIAS_ON);
  g2d.setRenderingHint(RenderingHints.KEY_RENDERING, RenderingHints.VALUE_RENDER_QUALITY);
  . . .
  . . .
}

The first is for shapes, the second is for text, and the third is to go for high quality (over speed).

Actually in 1.5 you can just pass -Dswing.aatext=true to the VM, but this didn't work with one of my applications for some reason.

Tags:

Drag & Drop from Linux (KDE, Gnome) File Managers (Konqueror, Nautilus) to Java Applications

I tried a few months ago to get drag & drop working from Konqueror to a Java application but it didn't work. Two programmers (myself and another) each had a crack at it and couldn't get it to work. I found one link through Google that seemed to be promising (see reply 23 or 23) but that didn't work. Then finally today by using slightly different keywords in my Google searching, I managed to find this link, which led me to this bug report. It turns out the "workaround" works great and I got it working. Works with Konqueror as well as Nautilus. Haven't tried any other Qt/KDE or GTK applications. Should work with Windows as well of course. I am attaching a trimmed down version of the workaround version with only the essentials to get this working. It it a lot nicer looking than the forum.sun.com link above. I had such a tough time finding the solution to this online, I hope others find this blog post and thus have an easier time at it than I did.

AttachmentSize
Plain text icon TestDragDropLinux.java_.txt3.46 KB

Java float vs. double and micro-optimization

Some people at work implemented a few classes all with floats and I am sick and tired of casting everything into float. There is absolutely no reason why floats should have ever been used. The original reason was because of memory and/or network and/or diskspace issues which is all now totally irrelevant because the project that these classes were mostly used for has now been scrapped. I recently ripped out a few classes from that project, however, because they are useful. I am finding them extremely annoying to use, however. Not only do they use floats but they are totally micro-optimized in other ways as well. I'm probably rewrite the class soon anyways so that it is readable. My opinion is that there is no reason to ever use anything other than ints, doubles, and bytes in Java. At leas in 2 years I have never come across any reason. Part of this is Java's fault for having two floating point types in the first place. I would have been much happier had this all been developed in Python.

Tags:

Sun to Release Java Under GPL

Looks like Sun is finally releasing Java under an open-source license. The GPL v2 to be precise, and not the "Sun-conceived Community Development and Distribution License (CDDL)" as it has with other projects. It will be managed by a new community that will spring up called "Open JDK". I am looking forward to this. The main thing I hope this brings is more features and quicker bug-fixes. Hopefully the open-sourcing of Java will allow more developers to be involved and hence allow it to be improved at a quicker pace than it has in the past.

Tags:

Hibernate-3.2.x/JDBC-3.1.x Does Not Work With MySQL 4.1.x

I just spent six hours today trying to figure out why the Hibernate example I set up and the example in the "eg" directory of the Hibernate binary distribution both did not work. The example I made was doing something really simple, filling in 3 attributes in a table. It was putting in garbage instead. The "auction" example that comes with Hibernate (in the "eg" directory) would just cack, leaving me with all sorts of confusing log messages.

Since the "auction" example worked at my work computer so I thought about what was different on that computer. I then thought that my work computer might have been using mysql-5, while my home computer is still using mysql-4.1.x. I had tried upgrading to mysql-5 a few months ago but it didn't work for some reason. I tried following the instructions for upgrading mysql on gentoo again and they worked flawlessly. I tried running the hibernate auction example by typing ant eg and it worked. Next I tried running the example I made myself and it worked as well. Finally, 6 hours later, and it looks like the solution was to upgrade to mysql-5.x.

I have no idea why mysql-5.x works but mysql-4.1.x would not. I would be surprised if my example or the auction example were making use of any new mysql 5 features. It's been a painful day, but at least it is fixed now. Now I can finally continue working to understand Hibernate.

Subscribe to RSS - java