Java is a first-class object-oriented language. With the exception of
primitive data types, everything in Java is an object. Even an array is
an Object. Every class creates instances that are objects. There is no
way of defining just a function / method which stays in Java all by
itself. There is no way of passing a method as argument or returning a
method body for that instance.
Since the old days of Swing, we
always had written anonymous classes if we wanted to pass some
functionality to any method. For example the old event listener code
used to look like:
Here
we wanted to add some custom code to Mouse listener. We defined an
anonymous inner class MouseAdapter and created its object. This way we
passed some functionality to addMouseListener method.
In short, it
is not easy to pass plain methods / functionalities in Java that can be
passed as arguments. Due to this limitation Java 8 adds a brand new
language level feature called
Since its beginning, the
Java language hasn’t evolved much if you ignore some of the features
like Annotations, Generics etc. Mostly during its life Java always
remained Object first language. After working with functional language
like JavaScript, it becomes clear to one how Java enforce its strict
object-oriented nature and strict typed on the source code. You see
Functions are not important for Java. On their own they cannot live in
Java world.
Functions
are first class citizens in a functional programming language. They
exists on their own. You can assign them to a variable and pass them as
arguments to other functions. JavaScript is one of the best example of
an FP language. There are some good articles
here and
here
that clearly describes the benefits of JavaScript as a functional
language. A functional language provides very powerful feature called
Closure that has quite a few advantages over traditional way of writing
applications. A closure is a function or reference to a function
together with a referencing environment — a table storing a reference to
each of the non-local variables of that function. Closest thing that
Java can provide to Closure is Lambda expressions. There is significant
difference between a Closure and Lambda expression, but at least Lambda
expression provides a good alternative to Closure.
In his quite sarcastic and funny
blog post,
Steve Yegge describes how Java world is strictly about Nouns. If you
haven’t read his blog, go first read it. It’s funny, its interesting and
it describe the exact reason why Java had to add Lambda expressions.
Lambda
expression adds that missing link of functional programming to Java.
Lambda expression let us have functions as first class citizen. Although
this is not 100% correct, we will shortly see how Lambda expressions
are not closures but they are as much close as we can get to closures.
In languages that support first class functions, the type of the lambda
expression would be a function; but in Java, the lambda expressions are
represented as objects, and so they must be bound to a particular object
type known as a functional interface. We will see in detail what
Functional interface are.
Here is a
nicely written article
by Mario Fusco on Why we need Lambda Expression in Java. He explains
why a modern programming language must have feature like closures.
Introduction to Lambda Expressions
A lambda expression is an anonymous function (not 100% true for Java
but lets assume it for time being). Simply put, it’s a method without a
declaration, i.e., access modifier, return value declaration, and name.
It’s
a shorthand that allows you to write a method in the same place you are
going to use it. Especially useful in places where a method is being
used only once, and the method definition is short. It saves you the
effort of declaring and writing a separate method to the containing
class.
Lambda expressions in Java is usual written using syntax
(argument) -> (body)
.
For example:
(arg1, arg2...) -> { body }
(type1 arg1, type2 arg2...) -> { body }
|
Following are some examples of Lambda expressions.
( int a, int b) -> { return a + b; }
() -> System.out.println( "Hello World" );
(String s) -> { System.out.println(s); }
() -> 42
() -> { return 3.1415 };
|
Structure of Lambda Expressions
Let’s check the structure of lambda expressions.
- A lambda expression can have zero, one or more parameters.
- The type of the parameters can be explicitly declared or it can be inferred from the context. e.g.
(int a)
is same as just (a)
- Parameters are enclosed in parentheses and separated by commas. e.g.
(a, b)
or (int a, int b)
or (String a, int b, float c)
- Empty parentheses are used to represent an empty set of parameters. e.g.
() -> 42
- When there is a single parameter, if its type is inferred, it is not mandatory to use parentheses. e.g.
a -> return a*a
- The body of the lambda expressions can contain zero, one or more statements.
- If
body of lambda expression has single statement curly brackets are not
mandatory and the return type of the anonymous function is the same as
that of the body expression.
- When there is more than one
statement in body than these must be enclosed in curly brackets (a code
block) and the return type of the anonymous function is the same as the
type of the value returned within the code block, or void if nothing is
returned.
What are Functional Interfaces
In Java, a
Marker interface is an interface with no methods or fields declaration.
In simple words, marker interface is an empty interface. Similarly, a
Functional Interface is an interface with just one abstract method
declared in it.
java.lang.Runnable
is an example of a Functional Interface. There is only one method
void run()
declared in Runnable interface. Similarly ActionListener interface is
also a Functional Interface. We use Anonymous inner classes to
instantiate objects of functional interface. With Lambda expressions,
this can be simplified.
Each lambda expression can be implicitly
assigned to one of the interface called Functional interface. For
example we can create Runnable interface’s reference from lambda
expression like below:
Runnable r = () -> System.out.println( "hello world" );
|
This type of conversion is automatically taken care by compiler when we dont specify the functional interface.
For example:
new Thread(
() -> System.out.println( "hello world" )
).start();
|
So
in above code, compiler automatically deduced that lambda expression
can be casted to Runnable interface from Thread class’s constructor
signature
public Thread(Runnable r) { }
.
Few examples of lambda expressions and their functional interface:
Consumer<Integer> c = ( int x) -> { System.out.println(x) };
BiConsumer<Integer, String> b = (Integer x, String y) -> System.out.println(x + " : " + y);
Predicate<String> p = (String s) -> { s == null };
|
@FunctionalInterface
is a new interface added in Java 8 to indicate that an interface type
declaration is intended to be a functional interface as defined by the
Java Language Specification. Java 8 also declared number of Functional
Interfaces that can be used by Lambda expressions. @FunctionalInterface
can be used for compiler level errors when the interface you have
annotated is not a valid Functional Interface.
Following is an example of custom defined Functional interface.
@FunctionalInterface
public interface WorkerInterface {
public void doSomeWork();
}
|
As
its definition says, Functional Interfaces can have only one abstract
method. If you try to add one more abstract method in it, it throws
compile time error.
For example:
@FunctionalInterface
public interface WorkerInterface {
public void doSomeWork();
public void doSomeMoreWork();
}
|
Error:
Unexpected @FunctionalInterface annotation
@FunctionalInterface ^ WorkerInterface is not a functional interface multiple
non-overriding abstract methods found in interface WorkerInterface 1 error
|
Once the Functional interface is defined, we can simply use it in our API and take advantage of Lambda expressions.
For example:
@FunctionalInterface
public interface WorkerInterface {
public void doSomeWork();
}
public class WorkerInterfaceTest {
public static void execute(WorkerInterface worker) {
worker.doSomeWork();
}
public static void main(String [] args) {
execute( new WorkerInterface() {
@Override
public void doSomeWork() {
System.out.println( "Worker invoked using Anonymous class" );
}
});
execute( () -> System.out.println( "Worker invoked using Lambda expression" ) );
}
}
|
Output:
Worker invoked using Anonymous class
Worker invoked using Lambda expression
|
Here
we created our own Functional interface and used to with lambda
expressions. execute() method can now take lambda expressions as
argument.
Examples of Lambda Expression
Best way of learning about Lambda expressions is by examples. Following are few examples:
Thread can be initialized like following:
new Thread( new Runnable() {
@Override
public void run() {
System.out.println( "Hello from thread" );
}
}).start();
new Thread(
() -> System.out.println( "Hello from thread" )
).start();
|
The
event handling can be done with Java 8 using lambda expression.
Following code we show both old and new way of adding ActionListener to a
UI component.
button.addActionListener( new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
System.out.println( "The button was clicked using old fashion code!" );
}
});
button.addActionListener( (e) -> {
System.out.println( "The button was clicked. From lambda expressions !" );
});
|
Simple
code to print all elements of given array. Note there is one more way
of using lambda expression. In below example we use the usual way of
creating lambda expression using arrow syntax and also we used a brand
new double colon (::) operator that Java 8 has to convert a normal
method into lambda expression.
List<Integer> list = Arrays.asList( 1 , 2 , 3 , 4 , 5 , 6 , 7 );
for (Integer n: list) {
System.out.println(n);
}
List<Integer> list = Arrays.asList( 1 , 2 , 3 , 4 , 5 , 6 , 7 );
list.forEach(n -> System.out.println(n));
list.forEach(System.out::println);
|
In
this example we use Predicate functional interface to create a test and
print the elements that pass the test. This way you can provide the
logic using lambda expression and do something based on it.
import java.util.Arrays;
import java.util.List;
import java.util.function.Predicate;
public class Main {
public static void main(String [] a) {
List<Integer> list = Arrays.asList( 1 , 2 , 3 , 4 , 5 , 6 , 7 );
System.out.println( "Print all numbers:" );
evaluate(list, (n)-> true );
System.out.println( "Print no numbers:" );
evaluate(list, (n)-> false );
System.out.println( "Print even numbers:" );
evaluate(list, (n)-> n% 2 == 0 );
System.out.println( "Print odd numbers:" );
evaluate(list, (n)-> n% 2 == 1 );
System.out.println( "Print numbers greater than 5:" );
evaluate(list, (n)-> n > 5 );
}
public static void evaluate(List<Integer> list, Predicate<Integer> predicate) {
for (Integer n: list) {
if (predicate.test(n)) {
System.out.println(n + " " );
}
}
}
}
|
Output:
Print all numbers: 1 2 3 4 5 6 7
Print no numbers:
Print even numbers: 2 4 6
Print odd numbers: 1 3 5 7
Print numbers greater than 5: 6 7
|
Some
wizardry using Lambda expression to print square of each element of a
list. Notice we used .stream() method to convert regular list into a
steam. Java 8 added some awesome Stream APIs.
java.util.stream.Stream
interface comes with tons of useful methods which can be used along
with lambda expression to do some voodoo. We passed a lambda expression
x -> x*x
to map() method which applies this to all elements of the stream. After that we use forEach to print the all elements of list.
List<Integer> list = Arrays.asList( 1 , 2 , 3 , 4 , 5 , 6 , 7 );
for (Integer n : list) {
int x = n * n;
System.out.println(x);
}
List<Integer> list = Arrays.asList( 1 , 2 , 3 , 4 , 5 , 6 , 7 );
list.stream().map((x) -> x*x).forEach(System.out::println);
|
Given
a list, sum the square of each element from this list. See how Lambda
expression can be used to achieve this in a single statement. This is
also a starters example on MapReduce. We used map() to square each
element and then reduce() to reduce all elements into single number.
List<Integer> list = Arrays.asList( 1 , 2 , 3 , 4 , 5 , 6 , 7 );
int sum = 0 ;
for (Integer n : list) {
int x = n * n;
sum = sum + x;
}
System.out.println(sum);
List<Integer> list = Arrays.asList( 1 , 2 , 3 , 4 , 5 , 6 , 7 );
int sum = list.stream().map(x -> x*x).reduce((x,y) -> x + y).get();
System.out.println(sum);
|
Difference between Lambda Expression and Anonymous class
One key difference between using Anonymous class and Lambda expression is the use of
this
keyword. For anonymous class ‘this’ keyword resolves to anonymous
class, whereas for lambda expression ‘this’ keyword resolves to
enclosing class where lambda is written.
Another difference
between lambda expression and anonymous class is in the way these two
are compiled. Java compiler compiles lambda expressions and convert them
into private method of the class. It uses
invokedynamic
instruction that was added in Java 7 to bind this method dynamically. Tal Weiss has
written a good blog on how Java compiles the lambda expressions into bytecode.
That’s All Folks
Mark Reinhold, Oracle’s Chief Architect,
describes
Lambda expressions as the single largest upgrade to the programming
model ever — larger even than generics. And why not. It gives Java
programmer the edge that it lacked compared to other functional
programming languages. Along with other features like
Virtual extension methods, Lambda expression can be utilized to write some really good code.
I hope this article gave a glimpse of what’s in the store for us in Java 8. Ciao :)
Ref : http://viralpatel.net/blogs/lambda-expressions-java-tutorial/