Sunday, March 9, 2008

More First Class Methods Code

I'm still experimenting with the prototype implementation of the FCM closures proposal. Here are a few utility methods that immediately came to mind.

withLock -- This one I've seen an example of online a few times. It automatically release the lock when the block of code finishes executing.
public static void withLock(Lock lock, Runnable task) {
lock.lock();
try {
task.run();
} catch (Exception e) {
throw e;
} finally {
lock.unlock();
}
}
Example Usage:
final ReentrantLock lock = new ReentrantLock();
withLock(lock, #{
// call some important locked code
});
Now I'm not too fond of unchecked Exceptions, but rethrowing is still better then swallowing every exception that escapes the Runnable. Here is my second attempt.
private static interface ExceptionHandler {
public void uncaughtException(Runnable source, Throwable e);
}

public static void withLock(Lock lock, Runnable task, ExceptionHandler eHandel) {
lock.lock();
try {
task.run();
} catch (Exception e) {
eHandel.uncaughtException(task, e);
} finally {
lock.unlock();
}
}
Example Usage:
withLock(lock, #{
// do some code that needs to be locked.
// throw an exception to test the event handler.
throw new RuntimeException("year is even error");
}, #(Runnable source, Throwable e){
// inline implemented event handler.
e.printStackTrace();
}
);
Once side effect of this is now one might be able to write reusable exception handling code. There have been plenty of times where a method I'm executing throws an exception, but there is no real way for me to recover. All I can do is log the failure and continue on. I end up writing the same try catch block over and over. It would be nice to write something like this once and reuse it.
public class LogAndContinueExceptionHandler implements ExceptionHandler{
public void uncaughtException(Runnable source, final Throwable e) {
SwingUtilities.invokeLater(#{
Logger.getLogger("ErrorLogger").log(Level.SEVERE, e.getMessage(), e);
});
}
}
Example Usage:
withLock(lock, #{
// do some code that needs to be locked.
// throw an exception to test the event handler.
throw new RuntimeException("year is even error");

}, new LogAndContinueExceptionHandler());
I used this idea when exploring another area that might benefit from closures. The EDT thread scheduling methods.

invokeAndWait
public static void invokeAndWait(Runnable r, ExceptionHandler eHandel){
try {
SwingUtilities.invokeAndWait(r);
catch (InterruptedException e) {
eHandel.uncaughtException(e);
} catch (InvocationTargetException e) {
eHandel.uncaughtException(r, e.getCause());
}
}

public class AlertAndContinueExceptionHandler implements ExceptionHandler{
public void uncaughtException(Runnable source, final Throwable e) {
Runnable showMessageBox = #{
JOptionPane.showMessageDialog(null, e.getMessage());
};
if(SwingUtilities.isEventDispatchThread()){
showMessageBox.run();
}else{
SwingUtilities.invokeLater(showMessageBox);
}
}
}
Example Usage:
invokeAndWait(#{
JOptionPane.showMessageDialog(null, "Hello World");
}, new AlertAndContinueExceptionHandler());
simpleSwingWorker -- The simpleSwingWorker method is an attempt to apply closures to the simple case of, "do something off the EDT then do something ON the EDT".
public static void simpleWorker(final Runnable offEDT, final Runnable onEDT){
Thread bGround = new Thread(#{
offEDT.run();
SwingUtilities.invokeLater(onEDT);
});
bGround.start();
}
Example Usage:
simpleWorker(#{
System.out.println("sleep");
Thread.currentThread().sleep(1000);
System.out.println("start");
}, #{
JOptionPane.showMessageDialog(null, "Hello World");
});
I also wrote a blocking version based on invokeAndWait.
public static void simpleBlockingWorker(final Runnable offEDT, final Runnable onEDT){
Thread bGround = new Thread(#{
offEDT.run();
SwingUtilities.invokeAndWait(onEDT);
});
bGround.start();
}

Hay wait a second, invokeAndWait throws exceptions right? And yet the code as it stands compiles without issue. I think I may have found a bug in the FCM prototype.

Some may look at these examples and point out that this type of functionality may really fall into the realm of "control structures". There is some debate in the Java community as to weather the common man should be allowed to write their own control structures. Some prefer to leave this responsibility with the language designers. It is my opinion that once you make this type of code easy, then you already have allowed the common man to make their own control structures. In that case you might as well legitimize the pattern and provide as much support as it possible.

I look forward to the day when there is a Java Control Abstraction (JCA) prototype to play around with.

3 comments:

Stephen Colebourne said...

The current FCM prototype does not handle exceptions well. At least it is in the release notes...

Unknown said...

I guess I should have read them more carefully then, LOL. But it's no big deal anyways. I'm very impressed with how functional it is for a prototype.

Anonymous said...

Good for people to know.