Android Programming In Java - Android Events
Written by Mike James   
Monday, 30 July 2018
Article Index
Android Programming In Java - Android Events
Lambda Types
Closure

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. The problem is that there is no function type in Java. In its place 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. A lambda expression is just a way of creating an instance of this 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.

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

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

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.

Using a Lambda to Create an Event handler

Any object that can generate an event will have a seteventListener method which can be used to attach an onEventListener object to the event handler list. The name of the method and the object includes the name of the event.

So there is a

setOnClickListener

method which takes an

OnClickListener

object as its only parameter.

Notice that this naming system is entirely convention and not part of the Java language.

The OnEventListener objects are all derived from an interface of the same name which defines a single abstract method which acts as the event handler.

An interface is like a class but it simply defines the functions that a class has to support. If a class inherits or implements an interface then you have to write code for each function defined in the interface. You can think of an interface as a specification for a list of functions you have to write to implement the interface.

For example, OnClickListener is an interface which has the single method

onClick(View v)

defined. To use it as an event handler you have to create an instance that implements onClick and then add it to the event handler list using setOnClickListener. This is a simple but tedious process that involves a lot of boiler plate code – see later for details of how it can be done.

The good news is that as the OnEventListner is usually a SAM – a Single Abstract Method – we can use a lambda to create an instance and avoid a lot of round about coding.

For example to add a click event handler to a button without using the Designer we can use a lambda to create the event handler:

View.OnClickListener eventHandler= (view)->{
       ((Button) view).setText("I've been clicked");
     };

and add it to the button:

Button b=(Button) findViewById(R.id.button);
 b.setOnClickListener( eventHandler );

This two stage process makes clear what is happening and what role the lambda is playing but it isn’t the way the code would usually be written. In nearly all cases it is simpler to write the lambda within the setOnClickListener call:

b.setOnClickListener( view->{
         ((Button) view).setText("I've been clicked");
       };);

This makes it look as if the lambda is just a function that is called when the click event occurs and this isn’t a bad way to think about it when you can forget about the SAMs that make it actually work.

So using a lambda we can create event handlers very easily. All we have to do is use the setOnEventListener method and write a lambda as its first and only parameter to act as the event handler. The only complication is to make sure that we get the number of parameters correct in the head of the lambda and treat them correctly in the body. For example, while you don’t have to say that view is a View object in the head of the lambda you still have to know what type it is in the body of the lambda.

If you compare this to the alternative ways of doing the job you will realize how much code it saves.

You don’t have to know all of the alternative ways of creating an event handler but you will need to add the anonymous class to your tools as it is sometimes best when you cannot use a lambda. There are even handling interfaces that define more than one event handling function. These are not SAMs and so cannot be implemented using a lambda.



Last Updated ( Saturday, 04 August 2018 )