λ expressions are one of the new features introduced in Java 8. This is one of the core features epitomizing Java's realization of providing functional programming features. Java has managed to surprise everyone by withholding this
feature for a long time. Almost every other language – Lisp(s), C++,
Python, C#, F#, PHP have supported λ expression in one form or another for at least half a dozen years now.
So, what is a λ? How come such a weird name? Though the roots of the name can be traced back to λ calculus propounded by Church in the 30s, this post is not going to cover the math. Let's save λ calculus for some other day.
A λ expression for all practical purposes is an anonymous function. At first glance it may appear to be quite difficult to digest the notion of defining a function without a name. There can be a multitude of reasons for having this construct, but the primary reason for having a λ is to have code behave as data.
So, what is a λ? How come such a weird name? Though the roots of the name can be traced back to λ calculus propounded by Church in the 30s, this post is not going to cover the math. Let's save λ calculus for some other day.
A λ expression for all practical purposes is an anonymous function. At first glance it may appear to be quite difficult to digest the notion of defining a function without a name. There can be a multitude of reasons for having this construct, but the primary reason for having a λ is to have code behave as data.
Code as data
If you are a Lisper, you know code is data. For imperative
programmers, we will motivate with an example. Callback is age old concept in
program design. It's latest popular avtar was AJAX.
Let’s say subsystem A calls subsystem B over the network and
needs to process the results. But there are no performance guarantees meaning
there is no way of telling how long B might take to return the answer. One simple
solution in this kind of scenario is to let A continue its work and refactor
the code to be executed when B returns in a separate
method/function. This code is likely to be unique because no one else needs to
see this callback code. Thus, this callback method/function is a prime candidate for being anonymous. Before Java 8, we had to use anonymous classes to hold this method, with Java 8 you can declare and use an anonymous function. So a λ does not really add a new tool in your toolbox, it sharpens the ones you had since Java 1.1.
Syntax
A run-of-the-mill function/method has these sub-constructs –
- Name
- Return type
- Argument list
- Body
A λ does not have name so we are down to representing three
constructs – return type, arguments and the body. Before we look at the syntax
in Java, let’s look at the Python syntax. Let’s say we want to define a
function that returns twice of the argument passed to it. This is how you would
do it Python
>>> f = lambda num: num*2
>>> f(100)
Let’s look at the expression lambda num:num*2 . The keyword lambda
indicates that this is a λ, stuff before the : is the argument list and the
stuff after : is the body of the function. There is no way of squeezing
multiple statements in the body of the function. This of course may be a severe
handicap. Another noteworthy thing is that the body of the λ has a single
expression which evaluates to the return value. There is no explicit return
statement but whatever the expression evaluates to is the return value of the
lambda.
While we are at it, f = lambda … an anti-pattern,
something you should never do unless your purposes are purely instructive. The
reason becomes obvious once you find the type of f
>>> type(f)
So, after all we ended up with a function name and this the
reason we were able to call f(100)
Java on the other hand has a much better syntax
(comma separated parameters) -> {
statements
constituting the body
}
OR
(comma separated parameters) -> expression that would be the return value
There are some bitter rules that one needs to commit to his
memory –
- Curly braces are mandatory only when you have statements
in the function body. You can get rid of
them if you have exactly one expression. Remember the Python example? Java’s
syntax is definitely richer and with a good reason – the λ in Java are late by
almost a decade. As an example this is a valid λ – () -> new
ArrayList
() - If the λ has a single parameter and type of the parameter is automatically inferred the () before the -> operator is optional. This is valid a -> System.out.println(“Got ” + a)
- If a λ does not take any parameters then the -> operator needs to be preceded by an empty ().
Example
The most popular example of λ expressions is that of
Runnable – and with a good reason. A Runnable has exactly one method – public void run().
The code below shows syntax in Java 8.
public class ThreadDemo {
public static void main(String... args) {
//Java 7 way
Thread th7 = new Thread(new Runnable() {
@Override
public void run() {
System.out.println("I am the old way");
}
});
// Java 8 way
Thread th8 = new Thread(
() -> System.out.println("I am the new way")
);
th7.start();
th8.start();
}
}
Outputs
I am the old way
I am the new way
No surprises there. Don't forget to note the absence of semi colon in the λ expression. Your code will not compile if you place a ';' at the end. This is one of the main differences between expressions and statements.
Another widely publicized example in the world of λ expressions is that of ActionListener. You add an ActionListener to a widget to tell Swing what to do when certain Action(Event) occurs. This requires encapsulating the code. Traditionally, this was done using Anonymous classes in Java. The anonymous class would be the container for the code to be executed when the Action happened. This kind of containment just got better because you can now use anonymous functions instead of anonymous classes.
can't locate part-2. is there a part 2 at all?
ReplyDelete