Saturday, January 24, 2009

Quick Tip : Getting Eclipse to help spot common errors

Since Java is a statically typed language, the compiler is pretty good at spotting errors, but sometimes we do things that are syntactically correct, but which are semantically wrong; take for example the following code sample.

public class TestError {
  String personName;

  public TestError(String personName) {
       personName = persionName;
  }

  public int getNameSize() {
       return personName.length();
  }
}

The above code contains a common mistake, namely that the parameter personName is hiding the class field personName; all that's really happening is the parameter is getting re-assigned the value it originally had. The main problem with this kind of mistake is that the developer assumes the object state is full initialized after calling the constructor, but on calling the (admittely worlds most pointless) getNameSize() method a NullPointerException would be thrown.

There are a few ways that the above code could be corrected in order for the compiler to spot the error. One way is to set the personName class field to final, which tells the compiler the personName field MUST be assigned a value in the constructor, and thus ensures the object state is intialized correctly, i.e.:

public class TestError {
    final String personName;

    public TestError(String personName) {
  personName = personName;
    }

    public int getNameSize() {
  return personName.length();
    }
}

The compiler will now throw a "Blank field Person may not have been initialize" error and compilation will fail. This is good (and you should certainly make as many fields as you can final), but it doesn't help if we want to actually update the person name in a later method.

Another way we can give a hint to the compiler is to make the personName parameter final:

public class TestError {
    String personName;
    
    public TestError(final String personName) {
         personName = personName;
    }
    
    public int getNameSize() {
         return personName.length();
    }
}

Now the compiler won't let us modify the personName parameter and will throw a "The local field variable personName cannot be assigned" error, and again stop compilation. Setting parameters to final is probably a good idea, and a good way to state your intention to the compiler, but we probably don't want to do this on EVERY method.

Luckily Eclipse can come to our aid by spotting this, and other common potential issues. If we look at the original code in the Eclipse editor we see this:

Notice the yellow warning underline underneath the parameter assignment. Eclipse is giving us a warning that "The assignment to variable personName has no effect" (you can check this by hovering over the margin marker); That's pretty useful, but we tend to get use to, or just don't see, warnings. What we want to do is have Eclipse scream at us here's a mistake and halt compilation; fortunately for this blog post, this can be done.

The trick lies in the depths of the Eclipse preferences under the Java section. The following image shows the full path:

In the resulting dialogue on the right hand side you'll see several sub-options, but the one we're interested in is the Potential programming problems; when expanded it looks as follows:

By default this dialogue has all the options set to warning or ignore, which results in Eclipse waving pathetically at us rather than screaming. The option that would have protected our original code is Assignment has no effect (eg 'x = x'):. If we set this to error, Eclipse will now halt all compilation until it's fixed; our original code now looks like this in the editor :

We've now found the error at compilation, rather than during testing, when it could be much harder to track down. There are lots more options within the potential programming problems section and I encourage you to take a look and set the relevant ones; you can find more information about each one by pressing F1 in the dialogue and reading the Eclipse help.

Warning

These Eclipse compiler options are indeed a great help but PLEASE don't use them as a short-cut to writing good defensive code! In the given example above, the best way to write the code is to make the personName field final which not only protects against the object being set up correctly, it also tells future developers the intent of the personName field.

2 comments:

Anonymous said...

In your first example the reference to the parameter "personName" is misspelled as "persionName".

I typically name my parameters starting with a lowercase "a" (ie: aPersonName) to indicate that they are arguments to the method rather than a local or class member.

Bishop e. bernard Jordan said...

Thanks, I will bookmark this page and use it... really very help full blog.

Prophecy news watch