Java Lambdas, SAMs And Events
Written by Ian Elliot   
Tuesday, 14 November 2017
Article Index
Java Lambdas, SAMs And Events
Event Handling & Closure
Anonymous Classes

What is all the fuss about Java lambdas? Easy - they make passing functions to other functions much easier. In particular they make setting up event handlers in GUIs such as Swing fairly simple even if you can't always make use of them. This is the easy guide to lambdas. 

Modern Java
With NetBeans And Swing

largecover

Contents

  1. Why Java?
  2. Getting started with Java
  3. Introducing Java - Swing Objects
  4. Writing Code
  5. Command Line Programs
  6. User Interface - More Swing
  7. Working With Class
  8. Java Class Inheritance
  9. Java Data Types - Numeric Data
  10. Java Data Types - Arrays And Strings
  11. Building a Java GUI - Containers
  12. Advanced OOP - Type, Casting, Packages
  13. Value And Reference 
  14. Java Lambdas, SAMs And Events

 

As long as you can use Java 8 then you can use lambdas.

The latest versions of NetBeans and IntelliJ do a good job of supporting them out of the box so why not use them?

The very first thing to say is that Java lambdas are not like other lambdas.

They aren't the pure creation of a purpose built language but the best that can be done to implement something like a lambda within the existing Java way of doing things. However rather than criticise the Java lambda you should marvel at the clever way it has been integrated into what already existed.

First what is a lambda?

Everything in Java is an object and the only way a function can exist is as a method, i.e. as part of an object. Java 8 changed all of this with the introduction of lambda functions.

A lambda function is a function that doesn’t belong to an object.

That is, it isn’t a method and it can be passed as a parameter to another function. 

This is useful in all sorts of contexts, but it is particularly useful if you are programming in a GUI framework that uses events. An event handler is just a function that is called when the event occurs, but because every function in Java has to be a method of some object, before lambdas you had to pass a complete object that had the function as a method. Lambdas simplify event handling for one.

Creating a lambda

In Java 8 and later a lambda is a function that you can define using special notation.

The function doesn’t have a name, it is an anonymous function.

A lambda can also be stored in a suitable variable and passed to another function as a parameter.

You define a lambda by supplying a head with parameters and a body with code:

(parameter list) -> {

   code
   return something;
};

For example:

(a,b)->{
  return a+b;
}

If you are a long time Java programmer what will be most shocking, apart from the fact that this is a function that doesn't belong to an object, is that there are no type specifiers in this declaration. Don’t worry, a lambda expression is strongly-typed but the compiler infers the type of the parameters and the return type from the context.

The point is that lambda expressions are always passed as a parameter or assigned to a variable and it is the type of the parameter or variable that determines the types used in the lambda.

It is not an error to include the data type of the parameters, and you can do it if you think it makes things clearer, but it is always unnecessary.

For example, you could write:

(int a, int b)->{
            return a+b;
}

There are a few simplifications to the lambda notation.

If there is just a single parameter you can omit the parenthesis.

For example:

n ->{
     return -n;
}

If the body is a single expression you can omit the brackets and the return and the result of the expression will be automatically returned.

For example:

n -> -n;

defines the same function as given above or

(a,b)-> a+b;

If you use a return then you need the brackets.

These rules can make lambda expressions look very strange in your code and this might make it harder to read.

Don’t go for the shortest and most compact expression make sure your code is easy to understand.  

Lambda Types

You can’t actually use the lambdas that have been given in the previous section because they don’t have a target type which allows the compiler to work out the type of their parameters etc.

You can't even use them if you supply the parameter types because the lambda as a whole has to have a type not just the parameters.

The problem is that there is no function type in Java.

This goes back to the everything is an object and functions only exist as methods of objects philosophy.

In place of a function type we make use of what is often called a SAM – or a Single Abstract Method.

An interface with a single method defined is a SAM and you can regard it as defining the type of a function i.e. the single abstract method that it defines.

For example:

public interface Sum{
        int sum(int a, int b);
}

This is a SAM for the function sum which takes two ints and returns an int.

Notice that this is not the most direct way to define a function type because you have to define an object type i.e. the Interface Sum and then a method within it i.e. the sum function. This results in more code than is strictly necessary and a duplication of names - what do you call the interface and what do you call the function?

To use the SAM you have to create an instance of it and to do this you have to create a class that implements the interface and more specifically the function. This is even more code and the whole point of a lambda is avoiding having to create this code. 

A lambda expression is just a way of creating an instance of a SAM without having to create a class and then an instance.

For example:

   Sum adder = (a,b)->{
            return a+b;
        };

The lambda expression has its type inferred from the types in the target SAM. That is a and b are ints and the return type is an int. The connection between the lambda and the SAM goes even deeper. The lambda actually creates an object of the type Sum with the abstract method defined by the body of the lambda. 

That is even a lambda function is actually a method of some object.

What this means is that if you want to call the function defined by they lambda you have to write:

int ans=adder.sum(1,2);

That is adder is an instance of the Sum interface with the lambda function as the implementation of its sum function. 

As I said at the beginning Java lambdas are not like other lambdas - they are not pure detached functions, they are still methods that belong to objects. 

This seems confusing at first but Java hasn’t given up the use of SAMs it has simply added lambdas as an easy and more direct way of creating an instance of a SAM.

Most of the time you can ignore the SAM that the lambda is implementing because it is generally predefined for you.

The existing libraries are all constructed using SAMs to pass functions to other functions. Before Java 8 you had to write a lot of code to create an instance of a SAM and pass it to the function. Now you can just use a lambda of the correct type.



Last Updated ( Tuesday, 14 November 2017 )