Bookmark and Share

Reducing anonymous inner class litter

Argh, how often we have to look at this kind of code:

EventQueue.invokeLater(new Runnable(){
    public void run() {
        doSomething();
    } 
});

Or, as one-liner,

EventQueue.invokeLater(new Runnable(){public void run(){doSomething();}});

All this mess to just put doSomething(); on a queue! This, if something, is an archetype of accidental complexity.

What if we could just build the required Runnable with a factory?

EventQueue.invokeLater(RunnableFactory.get(this, "doSomething"));

Well, we can! Here:

public class RunnableFactory { /** * Returns a {@link java.lang.Runnable} whose {@link java.lang.Runnable#run()} * invokes the given method on the given object with the given parameter(s). * * @param invokeOn * @param methodName * @param withParameters * @return {@link java.lang.Runnable} * @throws RuntimeException if any problem is encountered */ public static Runnable get(final Object invokeOn, final String methodName, final Object... withParameters) { return new Runnable() { public void run() { Class<?>[] parameterTypes = new Class<?>[withParameters.length]; for (int i = 0; i < withParameters.length; i++) { parameterTypes[i] = withParameters[i].getClass(); } try { java.lang.reflect.Method method; method = invokeOn.getClass().getMethod(methodName, parameterTypes); method.invoke(invokeOn, withParameters); } catch (Exception ex) { throw new RuntimeException(ex); } } }; } }

There are several cons in this “clever” approach, though:

  • Circumvents all compile-time checking.

  • Refactoring tools won’t reach literal method names ("doSomething").

  • Using reflection is a performance hit.

  • Even though the anonymous inner class Runnable technique looks horrible, it’s nevertheless a common idiom. Most programmers’ eyes will immediately recognize the essential content there. Not so with RunnableFactory.

Well, it’s a proof of concept, anyway :-)

Note that we could easily pull out almost everything out from the run() method. This way most of the performance hit (and most of the possible RuntimeExceptions) would fall onto the creation moment of the Runnable, instead of its execution moment. This might indeed be preferable form, at least when sending Runnables into busy queues:

public class RunnableFactory { /** * Returns a {@link java.lang.Runnable} whose {@link java.lang.Runnable#run()} * invokes the given method on the given object with the given parameter(s). * * @param invokeOn * @param methodName * @param withParameters * @return {@link java.lang.Runnable} * @throws RuntimeException if any problem is encountered */ public static Runnable get(final Object invokeOn, final String methodName, final Object... withParameters) { Class<?>[] parameterTypes = new Class<?>[withParameters.length]; for (int i = 0; i < withParameters.length; i++) { parameterTypes[i] = withParameters[i].getClass(); } final java.lang.reflect.Method method; try { method = invokeOn.getClass().getMethod(methodName, parameterTypes); } catch (Exception ex) { throw new RuntimeException(ex); } return new Runnable() { public void run() { try { method.invoke(invokeOn, withParameters); } catch (Exception ex) { throw new RuntimeException(ex); } } }; } } Last modified: 2010-06-05 12:23 +0300


blog comments powered by Disqus