Monday, March 10, 2008

Try and Try Again

While working on the code in my last post it occurred to me that reusable exception handling was decent idea. It might even be nice to create a version of try that takes a parameter that handed specific types of exceptions.

Example:
try {
FileReader fr = new FileReader("Readme.txt");
fr.read();
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
A enhanced version might look like this.
try(new LogAndContinueExceptionHandler()){
FileReader fr = new FileReader("Readme.txt");
fr.read();
}
LogAndContinueExceptionHandler looks like this.
private static interface ExceptionHandler {
public void uncaughtException(Runnable source, Throwable e);
}
public class LogAndContinueExceptionHandler implements ExceptionHandler{
@Override
public void uncaughtException(Runnable source, final Throwable e) {
Logger.getLogger("ErrorLogger").log(Level.SEVERE, e.getMessage(), e);
}
}
If all you are going to do is log the exception, then maybe a default implementation in Logger makes sense.
try(Logger.logALL("MyLogName")){
FileReader fr = new FileReader("Readme.txt");
fr.read();
}
And for all of you who think checked exception are the bane of all existence there is this option.
public class ToRuntime implements ExceptionHandler{
@Override
public void uncaughtException(Runnable source, final Throwable e) {
throw new RuntimeException(e);
}
}
This rethrows any exception it gets a hold of as a runtime exception. This would drive me nuts, but some people really do hate checked exceptions.

It would be nice to be able to supply different logic for different types of exceptions, just like you do in a try/catch block. Also if one could handle some logic in the reusable section and override that by implementing a catch block you could get more flexibility.

Example:

try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
} catch (ClassNotFoundException e1) {
e1.printStackTrace();
} catch (InstantiationException e1) {
e1.printStackTrace();
} catch (IllegalAccessException e1) {
e1.printStackTrace();
} catch (UnsupportedLookAndFeelException e1) {
e1.printStackTrace();
}

try(new ReflectionHandeler()){
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
} catch (UnsupportedLookAndFeelException e1) {
e1.printStackTrace();
}

public class ReflectionHandeler implements ExceptionHandler{
public void uncaughtException(Runnable source, final ClassNotFoundException e) {
// do something important
}

public void uncaughtException(Runnable source, final InstantiationException e) {
// do something important
}

public void uncaughtException(Runnable source, final IllegalAccessException e) {
// do something important
}
}

ReflectionHandeler might be useful someplace else... Ok this wasn't the best example, but you get the idea. Some get caught in the handler and some get caught in the catch.

Where a pattern for handling an exception or types of exceptions is repeatable building a reusable part can help unclutter and your code and make it more maintainable. Now if the task of handling a particular type of exception changes code need only be changed in one place, not scattered throughout the code in try blocks.

It's an idea. I may try to hack the javac compiler to support something like this... not that I'm sure even where to begin.

5 comments:

Casper Bang said...

Nice idea! May I recommend trying it in Kijaro, the no-nonsense sandbox set up by Stephen Colebourne?

david said...

It's similiar to the control invocation syntax of the BGGA proposal, right? http://www.javac.info/closures-v05.html

aberrant said...

@Casper

Thanks, Yes I really should try to implement this. I'll have to see if Kijaro will except me.

@David

It does turns out to look like the the control invocation syntax. It's not really a closure. It's just a delegate object for the exception handling logic.

Shams said...

Cool Idea,
really useful if only want to be doing logging or some common tasks on the exceptions.
But I think it will become more verbose when you need to have different exception handling codes in different scenarios.

Denis Bredelet said...

The problem with a non-local exception handler is that you have no access to local variables. Maybe you could pass some of them to the handler?