Wednesday, February 17, 2010

Beware of the SwingWorker

The SwingWorker is a nice class for executing long running tasks behind that won't block the event dispatch thread, but it has its gotchas that can be difficult to track down. The one in particular that has been the most cause of pain for me is that it swallows exceptions in the doInBackground method unless you explicitly call the get method from the done method.

Consider this seemingly simple code

SwingWorker w = new SwingWorker() {
@Override
protected Object doInBackground() throws Exception
{
throw new RuntimeException("Catch me");
}
};
w.execute();

Of course this throws an exception, right? In fact, it doesn't (well, it does but it never bubbles up so it would go completely unnoticed).

The way to ensure the exception is thrown is by calling get in the done method.


@Override
protected void done()
{
try
{
get();
}
catch (InterruptedException e)
{
throw new RuntimeException(e);
}
catch (ExecutionException e)
{
// throw the cause since the execution exception wraps the
// underlying exception
throw new RuntimeException(e.getCause());
}
}


It's an ugly solution though since the get method throws those checked exceptions but at least the exception gets thrown.

This is a very common problem when the swing worker is not returning any value and just performing a task, so you never call the get method.

Thursday, February 11, 2010

Difficulties of the Java clone method

Sometimes we have a need to copy objects. The clone method is a common way of doing that, but it is all too often misused. This post will discuss some common pitfalls and alternatives to cloning.

First, the Cloneable interface doesn't enforce any contracts. It has no methods. The clone method belongs to Object. Cloneable is just a marker interface to indicate that an object supports cloning. However, in order to make the clone method accessible to other objects, you need to make it public, since it is protected by default (and now all subclasses will have a public clone method, even if they are not directly cloneable since the visibility of the method can't be reduced, so be sure to implement clone for the subclasses).

Additionally, reading the clone method documentation a little more closely, it states the the following are generally true, but not requirements.
x.clone() != x
x.clone().getClass() == x.getClass()
x.clone().equals(x)

Even the stated contract of clone is quite vague, and there really is no guarantee of the object that will be returned. But working on the idea that we want a meaningful clone method, let's assume these will be true and move on to common problems with clone.

First, all objects in the hierarchy must implement clone, and you can't always control that. An implementation of clone will generally look like:

public class CloneMe extends NotCloneable implements Cloneable {
public CloneMe clone() {
try {
// This will fail if NotCloneable doesn't implement the clone method
CloneMe clone = (CloneMe) super.clone();

// copy the other fields
}
catch(CloneNotSupportedException e) {
// do something with the exception
}
}
}

It is difficult to copy objects in the object graph if they too don't
implement clone

public class CloneMe implements Cloneable {
private MyInterface obj;

public CloneMe clone() {
// try/catch omitted for brevity
CloneMe clone = (CloneMe) super.clone();
clone.obj = How can this be copied? We don't even know the type of MyInterface?.
Ideally use obj.clone(), but if it doesn't implement Cloneable, it's
impossible to make a deep copy (if the underlying type has a clone method,
it might be possible to reflectively invoke it).

}
}

Though the above example is illustrated by the fact that obj is an interface, it could have the same problem even if it is a non-final class.

Cloning lists and arrays must also clone the elements of the arrays

public class CloneMe implements Cloneable {
private Object[] myArray;
public CloneMe clone() {
CloneMe clone = (CloneMe) super.clone();
clone.myArray = Arrays.copyOf(myArray); // These arrays refer to the same elements
and modifying one's elements will modify the other's

}
}


Objects that implement clone can't clone final fields. Consider the class

public class CloneMe implements Cloneable {

private final Date myDate;

public CloneMe clone() {
// note: try/catch omitted for brevity
CloneMe clone = (CloneMe) super.clone();

// This won't compile since myDate is final
// This also illustrates a problem discussed above.
// What if date is actually a subclass of date? The clone and
// original objects will have different types for myDate.
clone.myDate = new Date(myDate.getTime());

}
}

Note: If the fields are completely immutable, they don't need to be clone since they can't be changed.

These are some of the major problems with clone, and Joshua Bloch discusses these points as well in Effective Java.

If you need to copy objects, what are the alternatives?

You could use copy constructors. However, copy constructors still have the problem that all of the objects being copied need to be deep copied as well. And since objects being copied may be a subclass of the declared type, the only way to copy them would be to reflectively invoke its copy constructor (if it has one).

You could write your own interface that has a copy method. It would function similarly to the clone method, but it would actually enforce some contract.

The best situation is to avoid object copying whenever possible (create totally new objects if needed). Favor immutability to avoid the need for clone and beware of the pitfalls and document well when copying is absolutely need it.

Tuesday, February 2, 2010

What to do when you find a bug

Inevitably you will find bugs in your code (yes, even you will write bugs). Once a bug has been identified, what steps do you take to fix it? Regardless of how small the bug is, it should be put into a bug tracking system (you do have one, right? If not, consider something free like Trac). This allows you to track bugs over time and do some deeper analysis.

Once the bug is identified, take steps to reproduce the bug by writing a test that exercises the bug. Then make the code change to fix the bug. Now you've fixed it and have a test to ensure it doesn't happen again.

This is where too many people stop. It is important to identify why the bug occurred. Was it an error in specifications? An error in coding logic? or some other error? Note this in the tracking system.

Periodically, query the bug tracking system to get an idea of why these bugs are happening (root cause analysis) and take the organizational steps necessary to correct them.

Monday, January 4, 2010

JUnit Assumptions

This is a new feature I just learned about. JUnit has a class called Assume which allows you to make assumptions about the environment you're running in. If the assumption is not true, then the test is ignored (that is the default test runner's behavior).
For example, sometimes I have tests that are operating system specific and don't necessarily make sense on other operating systems. Typically, I would do something like:

@Test
public void windowsSpecificTest() {
if ( System.getProperty("os.name").toLowerCase().contains("win") ) {
// do windows test
}
else {
LOGGER.warn("Test skipped because not on windows");
}
}

With the Assume class, you could do something like:

@Test
public void windowsSpecificTest() {
Assume.assumeTrue(System.getProperty("os.name").toLowerCase().contains("win"));
// do windows test. if this is windows, the test will be ignored.
}


This isn't earth shattering, but it's another nifty little trick.

Sunday, November 8, 2009

Java on the Decline?

I attended the No Fluff Just Stuff conference in Reston, VA this weekend (http://www.nofluffjuststuff.com/home/main), and once again it was excellent. One fact that is becoming clearer is that Java really is on the decline. With languages like Groovy and Scala (and Clojure - though I have no firsthand experience with that so I can't give much input there) on the rise, why should we still use Java?

I've been using groovy for the last year or so and use it in both tests and production code. Groovy is growing in popularity very quickly since it is just a dialect of Java, and all Java code is valid in Groovy. Developers can "groovify" code as they become more familiar with the Groovy idioms.

Scala is a bit newer to me, but I'm becoming familiar with that as well. At first I wondering why I needed language that could be both functional and OO, but it quickly became familiar. The functional aspect of Scala (and some of these operations are available in Groovy too) works magic on collections. Mapping operations to collections is a really nice feature. Think of all the times in Java you write code that looks something like this:

List myList// assume this is initialized
for ( MyObj o : myList ) {
System.out.println("o = " + o);
}

whereas in scala, the same code can be written as:

myList.foreach(n=> println(n))

This is a simple example, but any function can be mapped to every element in the list, which can be a real space saver.
I'm not going to try and write a Groovy or Scala tutorial here since there are already so many of those, but my takeaway is that these languages are on the rise, because they offer everything Java has to offer and more (with less code).

Monday, November 2, 2009

Immutable Collections

When we think of immutability in Java, the final keyword should come to mind. It's good practice to finalize whenever possible, particularly when working with multi-threaded applications. The less mutable state that exists, the less chance for side effects and bugs.
Working with collections is a bit trickier. When a class has a getter for a collection, things get a bit more difficult. Let's see what happens.

private final Collection<Object> aCollection;
public MyClass(Collection<Object> coll) {
aCollection = new LinkedList<Object>(coll);
}
public Collection<Object> getCollection() {
return aCollection;
}

Attempting to finalize a collection like this provides very little assurance that the collection will not be mutated. A client that calls getCollection can add or remove from the underlying collection as well as change the elements.
Addressing the first issue of adding or removing from the collection is easy to handle, yet I often see this overlooked. By using the Collections.unmodifiableXXX methods, we can easily create a collection that cannot be added or removed from. The constructor would now look like

public MyClass(Collection<Object> coll) {
aCollection = Collections.unmodifiableCollection(coll);
}

By finalizing in the constructor, this assures that neither private nor public methods can inadvertently mutate the structure of the list. The issue preventing a client from mutating the state of the objects in the list still exists. In order to prevent this, the objects would need to be completely immutable. There's not too much MyClass can do about this.
To sum up, try to make objects immutable whenever possible. You should be defaulting to final objects and unmodifiable collections and removing these restrictions only when absolutely necessary.

Wednesday, October 14, 2009

It's never too late for tests

So you've inherited a pile of buggy, spaghetti code, and now you're supposed to add some new features. We've all been there. It's very easy to say, "The code is already bad, so I'm not going to make the new features any nicer" but you shouldn't. This is your pile of spaghetti now, so you should work to make it incrementally better.

One big step in making bad code better is adding tests (I'm a firm believer in writing the tests first, so you shouldn't have much untested code, but it doesn't always happen). I'm not suggesting you drop everything and add tests to make sure you get to X% code coverage. But, as you add new features, you'll find yourself digging through old code. As you touch different parts of the code, refactor them where needed and add some tests. It will make you more confident in that part of the code, make life easier for yourself, and it will probably uncover some problems that you didn't know existed (and that have probably been there for a long time). A steady approach to testing will make any code better.