Saturday 17 January 2015

Power of Java 8 Lambda Expressions

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 whore 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:
//Old way:
new Thread(new Runnable() {
    @Override
    public void run() {
        System.out.println("Hello from thread");
    }
}).start();
//New way:
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.
//Old way:
button.addActionListener(new ActionListener() {
    @Override
    public void actionPerformed(ActionEvent e) {
        System.out.println("The button was clicked using old fashion code!");
    }
});
//New way:
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.
//Old way:
List<integer> list = Arrays.asList(1, 2, 3, 4, 5, 6, 7);
for(Integer n: list) {
    System.out.println(n);
}
//New way:
List<integer> list = Arrays.asList(1, 2, 3, 4, 5, 6, 7);
list.forEach(n -> System.out.println(n));
//or we can use :: double colon operator in Java 8
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.
//Old way:
List<integer> list = Arrays.asList(1,2,3,4,5,6,7);
for(Integer n : list) {
    int x = n * n;
    System.out.println(x);
}
//New way:
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.
//Old way:
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);
//New way:
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 thiskeyword. 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


No comments:

Post a Comment