This is a new way
in Java, one that will make our code more expressive, easier to write, less
error-prone, and easier to parallelize than we were able to do with Java until
now. This way has been around for decades and widely used in languages like
Lisp, Clojure, Erlang, Scala, Groovy, Ruby… This is not only a new way in Java,
but you’ll find it to be a better way as well.
Programmers
experienced with the functional style of programming in other languages who are
now involved in Java projects can use this book as well.
They can learn how
what they know translates to the specifics of the lambda expressions usage in
Java. Programmers who’re familiar with lambda expressions in Java can
use this book to help coach and train their team members who are getting up to
speed in this area.
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 };
</string></integer,></integer>
|
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);
</integer></integer>
|
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);
</integer></integer>
|
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);
</integer></integer>
|
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.
References :
http://viralpatel.net/blogs/lambda-expressions-java-tutorial/
http://docs.oracle.com/javase/tutorial/java/javaOO/lambdaexpressions.html#approach6