Neat Java 8 features - Lambda expressions

At work I’m still bound to Java 7, which is a bit a pity because since Java 8 there are some pretty neat features available.

This first of three posts is about Lambda expressions.

Next posts:

Lambda expressions

Lambda expressions allow you to pass functions on to methods, objects, etc.

E.g. you can create a function with the -> operator:

// A function which takes an Integer and returns a String:
Function<Integer, String> func = i -> {
    return  "This is '"+i+"'' as String";
};

You can then pass it on to another object, e. g.

someObject.setSomeFunction(func);

In the object you can make use of this function by calling its apply method

func.apply(100);

Here’s a complete example:

import java.util.function.Function;

public class Test {

    private Function<Integer, String> func;
    
    public void setFunction(Function<Integer, String> func) {
        this.func = func;
    }

    public String doSomething(int i) {
        return func.apply(i);
    }
    
    public static void main(String[] args) {
        Test test = new Test();
        
        Function<Integer, String> func = i -> {
            return "This is '"+i+"' as String";
        };
        
        test.setFunction(func);
        
        String result = test.doSomething(100);
        
        System.out.println(result);
    }
}

Instead of defining the function and then passing it on you more commonly see something like this, which is equivalent but shorter:

test.setFunction(i -> "This is '"+i+"' as String");

Function is a Functional interface, which means an interface which only has one abstract method. With the -> operator you effectively provide the implementation for this abstract method.

You can define your own Functional interfaces. Let’s say you have a Handler interface which provides a method to process a certain request, in this example case consisting of a String and an integer, but that could as well be an HTTP request, UI event, etc.

@FunctionalInterface
public interface Handler {
    public String handle(String item, int amount);
}

Annotate it with the FunctionalInterface annotation. It’s not necessary but helps spotting issues early!

You can use the Handler interface in other classes for example like this (directly providing an implementation via the -> operator):

public class Test {

    private Handler handler;
    
    public void setHandler(Handler handler) {
        this.handler = handler;
    }
    
    public String doSomething(String arg1, int arg2) {
        return handler.handle(arg1, arg2);
    }
    
    public static void main(String[] args) {
        Test test = new Test();

        test.setHandler((x, y) -> {
            return "Successfully handled " + x + " and " + y;
        });

        String result = test.doSomething("Test", 1);
        System.out.println(result);
    }
}

Where possible many core Java interfaces have been annotated with the FunctionalInterface Annotation, for example the Actionlistener, so that you can easily provide an implementation:

JButton button = new JButton("Click me");
button.setActionCommand("doSomething");
button.addActionListener(e -> {
    System.out.println("Handling event "+e.getActionCommand());
});

Coming back the Handler example: Instead of the ‘inline’ implementation …

test.setHandler((x, y) -> {
    return "Successfully handled " + x + " and " + y;
});

… you can of course use already implemented methods:

HandlerImpl h = new HandlerImpl();
test.setHandler(h::handle);

This :: syntax is a method reference (also a new feature of Java 8)

If this method is a static method, this could be even shorter as you don’t need an instance:

test.setHandler(StaticHandlerImpl::handle);

Next post: Neat Java 8 features - Stream API