Lambda Expression

Lets start this article with a familiared Java code which is used to create a new Thread using Runnable interface. Based on the requirements you might prefer either to create a separate class which implements java.lang.Runnable interface or to create an anonymous Runnable object and pass it to the Thread object and start it. In the following code I have chosen the second way and nothing to surprise with this code; it simply runs and prints the id of newly created Thread.
public class ThreadDemo {
    public static void main(String[] args) {
        // Runnable anonymous class
        Runnable runnable = new Runnable() {
            @Override
            public void run() {
                System.out.println("ID: " + Thread.currentThread().getId());
            }
        };
        Thread thread = new Thread(runnable);
        thread.start();
    }
}

Functional Interface
In the above code java.lang.Runnable interface has a single abstract method run():void. In Java 8 we call this type of interface as Functional interface.
Oracle defines the functional interface as follows:
"Conceptually, a functional interface has exactly one abstract method. Since default methods have an implementation, they are not abstract. If an interface declares an abstract method overriding one of the public methods of java.lang.Object, that also does not count toward the interface's abstract method count since any implementation of the interface will have an implementation from java.lang.Object or elsewhere."
To make it more clear, take two interfaces Runnable and Comparable...
The java.lang.Runnable interface has a single abstract method so obviously it is a functional interface
The java.util.Comparator interface has two abstract methods compare(T o1, T o2):int and equals(Object obj):boolean. However still it is a functional interface because the equals method is a redefinition of a method from java.lang.Object class

Java 8 also introduced an informative annotation @FunctionalInterface to mark an interface as a functional interface, which can be used as @Override annotation to get additional type checking support.
The implementation of a functional interface can be simplified using lambda expression in Java 8. The rules related to lambda expressions are covered later in this article, but before getting into the rules of lambda lets implement the above program using lambda expression to get an overview of lambda.

Lambda Implementation
public class LambdaThreadDemo {
    public static void main(String[] args) {
        // Runnable anonymous object
        Runnable runnable = () -> System.out.println("ID: " + Thread.currentThread().getId());
        Thread thread = new Thread(runnable);
        thread.start();
    }
}
The anonymous class has been turned into a single line lambda expression. This is how I understood the core idea of lambda expression; "Lambda expression is a modern way to create an anonymous class of a single abstract method interface (functional interface)". By looking at this simple example you can feel the advantage of using lambda expression rather than traditional anonymous inner classes. Lambda expressions let the developers to write less and keep the code clean. They have another advantage on accessing local variables and which is discussed at the end of this article.

The Syntax
A most general format of a lambda expression is: parameters -> expression. However there are some more rules, and which are covered here with a complete set of examples.

Rule #1:
A lambda expression must have the parameters of the functional interface method inside parantheses followed by an arrow -> and a code block.
public class LambdaRuleOne {
    public static void main(String[] args) {
        Printable printable = (String x, int y) -> {
            for(int i = 1; i <= y; i++) {
                System.out.println(x);
            }
        };
        doStuff(printable);
    }

    private static void doStuff(Printable printer) {
        printer.print("Hello", 5);
    }
}

interface Printable {
    public void print(String msg, int count);
}

Rule #2:
If the data types of the parameters are predictable, then you can omit the data types.
public class LambdaRuleTwo {
    public static void main(String[] args) {
        Printable printable = (x, y) -> {
            for(int i = 1; i <= y; i++) {
                System.out.println(x);
            }
        };
        doStuff(printable);
    }

    private static void doStuff(Printable printer) {
        printer.print("Hello", 5);
    }
}

interface Printable {
    public void print(String msg, int count);
}

Rule #3:
Even if a lambda expression has no parameters, you still supply empty parentheses.
public class LambdaRuleThree {
    public static void main(String[] args) {
        Printable printable = () -> {System.out.println("Hello world");};
        doStuff(printable);
    }

    private static void doStuff(Printable printer) {
        printer.print();
    }
}

interface Printable {
    public void print();
}

Rule #4:
If a method has a single parameter with inferred type, you can even omit the parentheses.
public class LambdaRuleFour {
    public static void main(String[] args) {
        Printable printable = x -> {System.out.println(x);};
        doStuff(printable);
    }

    private static void doStuff(Printable printer) {
        printer.print("Hello");
    }
}

interface Printable {
    public void print(String msg);
}

Rule #5:
If the lambda expression's body is just a single expression, then you can omit the curly brackets.
public class LambdaRuleFive {
    public static void main(String[] args) {
        Printable printable = (x, y) -> System.out.println(x + " : " + y);
        doStuff(printable);
    }

    private static void doStuff(Printable printer) {
        printer.print("Hello", 5);
    }
}

interface Printable {
    public void print(String msg, int count);
}

Rule #6:
If the expression body is just a single expression which needs to return something and if you have decided to omit the curly brackets, then do not use the return keyword.
public class LambdaRuleSix {
    public static void main(String[] args) {
        TaxCalculator calculator = x -> x * 0.02;
        doStuff(calculator);
    }

    private static void doStuff(TaxCalculator calc) {
        double tax = calc.calculate(100.00);
        System.out.println("TAX: " + tax);
    }
}

interface TaxCalculator {
    public double calculate(double amount);
}

Variable Scope
According to Java rules a method local anonymous class cannot access any non final local variables of that method. However the lambda expression uses a flexible rule according to that a lambda expression can use any effectively final local variable. For the instance and static variables same rules of method local anonymous classes are applied. Here effectively final means that the variable does not need to be defined as final but the lambda expression should not try to change the value of that local variable.

public class LambdaVariableScope {
    public static void main(String[] args) {
        String name = "Java Helps";
        Thread validLambda = new Thread(() -> System.out.println(name));
        /*Thread invalidLambda = new Thread(() -> {
            name = "Something else";// Cannot change the value
            System.out.println(name);
        });*/
        validLambda.start();
    }
}

Practice Problem
Following code sorts an array of Strings in the reverse order using an anonymous java.util.Comparator class. Replace the anonymous class with a suitable lambda expression. Try  to reduce the code as much as possible. (Answer is available in the Git Hub repository.)
import java.util.*;

public class LambdaExercise {
    public static void main(String[] args) {
    String[] array = {"Java", "C++", "Ruby", "Python"};
    System.out.println("Unsorted: " + Arrays.toString(array));
    Arrays.sort(array, new Comparator<String>() {
        public int compare(String x, String y) {
            return y.compareTo(x);
        }
    });
System.out.println("Reverse sorted: " + Arrays.toString(array));
    }
}

Find the source codes at Git Hub.
First

Contact Form

Name

Email *

Message *