Closure in Java: fast and nice!

This entry is part 6 of 19 in the series Programming Languages

Working for two very important Banks, I have the need to play with Closure in Java. I have a lot of trouble looking at a good description of the subject, until I read a post on StackOverflow.

I have decided to re-cook this subject, adding a my specialized Example also.

Let’s start!

In Java anonymous inner classes are effectively closures, so they can be used to emulate lambda expressions or “delegates”. For example, take this interface:

In Java

[java]public interface F<A, B> {
   public B f(A a);
}[/java]
You can use this anonymously to create a first-class function in Java. Let’s say you have the following method that returns the first number larger than i in the given list, or i if no number is larger:
[java]public static int larger(final List<Integer> ns, final int i) {
  for (Integer n : ns)
     if (n > i)
        return n;
  return i;
}
[/java]
And then you have another method that returns the first number smaller than i in the given list, or i if no number is smaller:
[java]public static int smaller(final List<Integer> ns, final int i) {
   for (Integer n : ns)
      if (n < i)
         return n;
   return i;
}
[/java]
These methods are almost identical.
Using the first-class function type F, we can rewrite these into one method as follows:
[java]<code>public static <T> T firstMatch(final List<T> ts, final F<T, Boolean> f, T z) {
   for (T t : ts)
      if (f.f(t))
         return t;
   return z;
}
</code>[/java]
You can use an anonymous class to use the firstMatch method:
[java]<code>F<Integer, Boolean>() greaterThanTen = new F<Integer, Boolean> {
   Boolean f(final Integer n) {
      return n > 10;
   }
}
int moreThanMyFingersCanCount = firstMatch(xs, greaterThanTen, x);
</code>[/java]

For instance let’s implement a Generic Cache Decorator as a Closure.

Generic Cache Decorator with Java Closure

Usage Example
We want to enable/disable a simple Cache Engine, keeping the code clean.
Is it possible to let a Client library to provide a Function,
and then use a special CacheDecorator to delegate how to use it…
Let’s try:

public interface CacheFun<KeyToCache extends Serializable,TypeToCache extends Serializable>
{
    /**
     * Funzione che implementa la business logic senza cache.
     * Verrà chiamata solo se necessario
     * @param key
     * @return
     * @throws Exception
     */
    public abstract TypeToCache f(KeyToCache key) throws Exception;
}

The Decorator:
[java]public class CacheDecorator {
static final boolean cacheEnabled;
static {
if(
System.getProperty("net.sf.ehcache.disabled")!=null
&amp;&amp;
System.getProperty("net.sf.ehcache.disabled").equals("true")
)
{
cacheEnabled=false;
}else{
cacheEnabled=true;
}
}

final static Logger logger = Logger.getLogger(CacheDecorator.class);

/**
*
* @param <K> Non può essere null
* @param <T>
* @param f
* @param key
* @param cache
* @return
*/
@SuppressWarnings("unchecked")
public static <K extends Serializable, T extends Serializable> T findOnCache(
final CacheFun<K,T> f,
final K key,
final Ehcache cache)
{
try {
String msg="CacheEngine["+key.getClass()+"] ";
long startTime = BasicObject.startTime();
if (cacheEnabled) {
Element elemento = cache.get(key);
if (elemento == null) {
elemento = new Element(key,f.f(key) );
msg += "Cache MISS:" + key + " Cache::" + cache.getName();
msg+="Usage Size:"+cache.getSize()+" / "+cache.getCacheConfiguration().getMaxElementsInMemory()+" "+
BasicObject.percentage(cache.getSize(), cache.getCacheConfiguration().getMaxElementsInMemory())+" %";
cache.put(elemento);
} else {
msg += "Cache Hit:" + key + " Cache::" + cache.getName();
}
logger.info(msg);
BasicObject.logTime(startTime, msg);
return (T) elemento.getValue();
} else {
BasicObject.logTime(startTime, msg+" **** CACHE DISABLED: " + key);
return f.f(key);
}
}catch(RuntimeException re){
logger.fatal("findOnCache FAILED:",
re);
throw re;
}catch (Exception exception) {
logger.fatal("findOnCache FAILED:",
exception);
throw new RuntimeException(exception);
}
}
}
[/java]
Usage
An example usage is:
[java][…]
final Cache cache = anEhaCache.getCacheManager().getCache("pfpSmallTimeCache");

// Phase1: Creazione della cache
final String expectedValue = "JQuery";
final String mykey = "MyLovedLibrary";

//Must Not Exist
cache.removeAll();
assertNull(cache.get(mykey));

final List<Integer> calledTimes=new ArrayList<Integer>();
CacheFun<String, Serializable> cacheDecoratorClosure = new CacheFun<String,Serializable>() {
@Override
public Serializable f(String key) throws Exception {
Serializable r;
if (key.equals("MyLovedLibrary")) {
r= expectedValue;
} else {
r= null;
}
calledTimes.add(1);
return r;

}
};
Serializable result = CacheDecorator.findOnCache(cacheDecoratorClosure,mykey, cache);
assertEquals(expectedValue, result);
assertNotNull(cache.get(mykey));

assertTrue(cache.getSize()==1);
[…]
[/java]
References

public interface CacheFun<KeyToCache extends Serializable,TypeToCache extends Serializable>
{
/**
* Funzione che implementa la business logic senza cache.
* Verrà chiamata solo se necessario
* @param key
* @return
* @throws Exception
*/
public abstract TypeToCache f(KeyToCache key) throws Exception;
}
Series NavigationJRuby and Jython: the easy wayPython 3.0 Release

6 Replies to “Closure in Java: fast and nice!”

Leave a Reply