Thursday, March 6, 2014

lambda to the rescue

I'm a big fan of lambda expressions in Java 8, but it was only recently that I was able to push some lambda code to OpenJFX.  The thing of it is, lambda expressions helped me in two ways. First, it got me looking at the problem I was trying to solve from a different angle. Second, it helped me eliminate a lot of duplicate code.

The problem I was trying to solve was one where I had two identical code paths. The only difference between the two was the data type of one of the parameters. Basically, I had

    private List<StylesheetContainer> gatherParentStylesheets(Parent parent)
and 
    private List<StylesheetContainer> gatherSceneStylesheets(Scene parent) 

The main difference between these two methods was a call to add the Parent to one list, and a call to add the Scene to a different list (the idea is that there is one list of Parents that refer to the stylesheet and another list of Scenes that refer to the stylesheet). I tried different ways of refactoring these methods into one and kept coming back to the same thought; that if I could pass both the parent or scene and the list as parameters, I'd be set.

I started to think about whether or not lambdas could help me. What if I passed a function that did that for me? What I really wanted to do was say that this Scene or Parent refers to the StylesheetContainer and I came up with this interface. 

    @FunctionalInterface
    static interface Referent {void addReferenceTo(StylesheetContainer c) } 

Now I could pass the "addReferenceTo" function to a method and could refactor the code into a single method.

    private List<StylesheetContainer> processStylesheets(List<String> stylesheets, StylesheetContainer.Referent referent)

In this method, I just do:

    referent.addReferenceTo(container);
 
And call it like so:

    final List<StylesheetContainer> list = processStylesheets(sceneStylesheets, (c) -> c.sceneUsers.add(scene));
or
    final List<StylesheetContainer> list = processStylesheets(parentStylesheets, (c) -> c.parentUsers.add(parent));

In retrospect, I could have done the same thing with an Interface and an anonymous inner class. Or I could have just used 'instance of'.  But I think the lambda solution is rather elegant.

You can see the change here, in the diffs to StyleManager.