June 1, 2008 12:00 AM

Throw Defect

Defects Sign

While I'm on the subject of exceptions, let me share another exception idiom I've used a lot on recent projects... the Defect exception.

The Java compiler is very strict. It will complain about missing code paths that you, the programmer, know should never be followed at runtime. This is especially common when using APIs that throw checked exceptions to process data that will always be correct unless the programmer has screwed up..

For example, loading and parsing template from a resource that is compiled into the application should never fail, but throws a checked IOException.

Template template;
try {
    template = new Template(getClass().getResource("data-that-is-compiled-into-the-app.xml"));
}
catch (IOException e) {
    // should never happen
}
...

If an IOException is caught, something is seriously wrong with the application itself, because of something the programmer has done. The application has been built incorrectly, perhaps, or the template is syntactically incorrect. If the application continues running it will fail with confusing errors later on. The error will be difficult to diagnose.

So, the catch block must throw another exception. It can't throw a checked exception. Because it has caught a programming error, it should throw some kind of RuntimeException. RuntimeException itself is a bit vague, and there isn't a subclass of RuntimeException that really fits the bill for this situation. Therefore, I like to define a new exception type to report programmer errors. I first called it StupidProgrammerException, but now, as suggested by Romilly, I call it by the less confrontational name of Defect:

public class Defect extends RuntimeException {
    public Defect(String message) {
        super(message);
    }

    public Defect(String message, Throwable cause) {
        super(message, cause);
    }
}

When the compiler asks me to write code paths that should never happen, I throw a Defect. For example:

Template template;
try {
    template = new Template(getClass().getResource("data-that-is-compiled-into-the-app.xml"));
}
catch (IOException e) {
    throw new Defect("could not load template", e);
}
...

Image by Jonas B, distributed under the Creative Commons Attribution license.

Posted on June 26, 2008 [ Permalink | Comments ]

Generic Throws: Another Little Java Idiom

throw.jpg

A seemingly little known fact about Java generics is that you can write generic throws declarations by declaring a type parameter that extends Exception. For example, the following interface defines a generic finder that looks up a value of type T, returns null if it is not found,or may report that the lookup failed completely by throwing an exception of type X:

public interface Finder<T, X extends Exception> {
    @Nullable
    T find(String criteria) throws X;
}

Different implementations can fail in different ways. A finder that performed an HTTP query can fail with an IOException. A finder that queries a database can fail with a SQLException. And so on.

A Cunning Idiom for Classes That Cannot Fail

But what about queries that cannot fail? You might want to implement the query in-memory, with a HashMap or something. You don't want to declare that find throws a checked exception. Therefore bind X to RuntimeException. The compiler will ignore the throws clause and you don't even need to include it in implementing classes:

public class InMemoryFinder<T> extend Finder<T, RuntimeException> {
    private final Map<String,T> entries;

    public InMemoryFinder(Map<String,T> entries) {
        this.entries = entries;
    }

    @Nullable
    T find(String criteria) { // No need for a throws clause
        return entries.get(criteria);
    }
}

Generic throws can remove a lot of boilerplate code to pass checked exceptions through interfaces by wrapping them in more abstract checked exceptions. Hopefully one day Java will provide anchored exceptions so we can avoid all this generics jiggery-pokery.

Generic Throws and Polymorphism

Wrapped exceptions are still necessary when an interface must be used polymorphically. A type that declares generic throws is generic but not polymorphic: an interface T<IOException> cannot be used wherever a T<SQLException> is acceptable.

If necessary, an interface with generic throws can be converted by an Adaptor into a version that throws wrapped exceptions and can be used polymorphically.

public class PolymorphicFinder<T,X> extend Finder<T, FinderException> {
    private final Finder<T,X> implementation;

    public PolymorphicFinder(Finder<T,X> implementation) {
        this.implementation = implementation;
    }

    @Nullable
    T find(String criteria) throws FinderException {
        try {
            return implementation.find(criteria);
        }
        catch (X x) {
            throw new FinderException("query failed", x);
        }
    }
}

Wishful Thinking

Imagine if the Iterable and Iterator interfaces were parameterised by exception type:

public interface Iterator<T, X extends Exception> {
    boolean hasNext() throws X;
    T next() throws X;
}

public interface Iterable<T, X extends Exception> {
    Iterator<T,X> iterator();
}

Collections could implement Iterable<T,RuntimeException> and appear no different from the way they are now. However, I/O streams, SQL result sets and other streams of data read from the program's environment could be represented as Iterable objects and the for-each loop could be used to iterate over their contents.

For example, BufferedReader could implement Iterable<String,IOException>, which would let you write:

try {
    BufferedReader reader = new BufferedReader(...);
    for (String line : reader) {
        ... do something with the line
    }
}
catch (IOException e) {
    ... iteration failed
}

Unfortunately, it's probably too late to make this change because it would break backward compatibility.

Photo by Wildcat Dunny, distributed under a Creative Commons license.

Posted on June 25, 2008 [ Permalink | Comments ]