Java 8 Lambda Expressions by Examples

Ever since I heard Java 8 is going to support lambda expressions (aka closures), I was very enthusiastic to spice my code with such a decent and concise functional element. Most developers extensively use Anonymous Inner Classes for event handlers, comparators, basic thread/runnable implementations, etc and overburden the logic with unnecessary scaffoldings even a very simple piece of code seems complex and unwieldy. Java 8 now added Lambda expressions as part of language syntax that help solve similar problem in a very elegant manner.

It enable developers to encapsulate a single unit of behavior and pass it to other code. It’s like syntactic sugar for an anonymous class (with one method whose type is inferred) and is an object-less method. I prefer avoiding extensive theoretical material in this post, but before moving further towards understanding the syntax, structure and examples of lambdas, there is an important concept need attention.

Functional Interface

A Functional Interface (aka Single Abstract Method type or SMA) is any interface that contains only one abstract method. But it may contain some static or/and default methods. java.lang.Runnable is an example of a Functional Interface, as it have only one run() method, which is abstract. Similarly ActionListener interface is also a functional interface. Following is an example of user defined functional interface.

1
2
3
4
interface Worker() {
 
    boolean doWork();
};

Have a look at another templatized functional interface example:

1
2
3
4
interface Operator {
 
    TYPE operate(TYPE operand1, TYPE operand2);
}

That’s it, as it’s a normal interface that just have one abstract method. Although there is more to talk on functional interface specially java 8′s provided package
java.util.function and @FunctionalInterface annotation but for now just focus on lambdas. I will cover these topic in detail in a separate post.

Lambda Expressions

Lambda expressions, also known as closures, are anonymous methods that provide developers with a simple and compact means for representing behavior as data.

- Brian Goetz, Specification Lead for JSR 335

To easily understand the syntax of a lambda expression we first take a look at conventional Anonymous Inner Class.

1
2
3
4
5
6
7
new Runnable() {
 
    public void run() {
 
        performWork();
    }
};

Lambda expressions provide the remedy for clumsiness of an Anonymous Inner Class and convert above five lines into a single line like.

1
() -> performWork();

Syntax and Structure

So, standard syntax of lambda is as follows:

1
() -> some expression

Or

1
(arguments) -> { body just like function }

A lambda expression consists of the following three parts:

  1. A comma-separated list of formal parameters enclosed in parentheses.
    1
    2
    3
    4
    5
    // Taking two integers and retuning their sum
    (int x, int y) -> x + y
     
    // lambda expression with single integer argument that returns its next integer value
    (int x) -> { return x + 1; }

    You can omit the datatype of the parameters in a lambda expression.

    1
    2
    3
    4
    // same lambdas without argument types
    (x, y) -> x + y
     
    (x) -> { return x + 1; }

    In addition, you can omit the parentheses if there is only one parameter.

    1
    2
    // single argument lambda without parentheses
    x -> { return x + 1; }
  2. The arrow token, ->
    1
    2
    3
    4
    5
    //Lambda taking no argument and returning a constant integer vale, 92
    () -> 92
     
    // taking a string as an argument and printing that on console
    (String s) -> { System.out.println(s); }
  3. A body, which consists of a single expression or statement block. In the expression form, the body is simply evaluated and returned.
    1
    2
    3
    4
    5
    // for single statement body, no need to use braces and the return statement
    x -> x + 1
     
    // simple lambda with void return type
    () -> System.out.println(“Hello World!”)

    In the block form, the body is evaluated like a method body and a return statement returns control to the caller of the anonymous method.

Ok, we spend enough on syntax of lambda, let’s move to some real examples

Examples of Lambda Expressions

To easily understand the lambda expressions, let’s start with some basic comparative examples with anonymous inner class. In the first example, we will see the use of lambda Comparator interface implementation. Assume we have a Person class with name property, and we constructed an array of Person objects, named persons.

1
2
3
4
5
6
7
8
9
10
11
Arrays.sort(persons, new Comparator() {
 
    @Override
    public int compare(Person first, Person second) {
 
        return first.getName().compareTo(second.getName());
    }
});
 
// it’s a standard sort but interestingly rather than passing Comparator object, it’s taking a lambda expression
Arrays.sort(persons,(first, second) -> first.getName().compareTo(second.getName()));

Notice that five lines of code turned into a single line, that’s the beauty of lambda over anonymous inner classes. Now let’s look at another example of Runnable implementation. And same is in the Runnable case.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
Runnable printer = new Runnable() {
 
    @Override
    public void run() {
 
        System.out.println("Hello, I’m inside runnable class...");
    }
};
 
printer.run();
 
printer = () -> System.out.println("Hello, I’m inside runnable lambda...");
 
printer.run();

Writing lambda expression for user defined functional interface is also very simple and easy. Following example uses Operator custom interface and stores lambda expression in a reference variable for the sake of reusability;

1
2
3
Operator addition = (op1, op2) -> op1 + op2;
 
System.out.println("Addition result: " + addition.operate(2, 3));

For further understanding, there is another example of lambda expressions with statement block.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
interface GenericOperator {
 
    TYPE operate(TYPE ... operands);
}
 
//lambda expression with statement block
GenericOperator multiply = numbers -> {
 
    int result = 0;
 
    for(int num : numbers)
        result *= num;
 
    return result;
};
 
System.out.println("Multiplication result: " + multiply.operate(2,3,4));

As demonstrated above, the block is just like a normal function block and lambdas are functional elements similar to methods, but with higher significance.

When to use Lambda expression

Lambdas are not actually the replacement of anonymous inner classes but a batter way to implement the single abstract method types. Both of them has their significance and are intended to use in their specific scenarios.

  • Lambda expression are meant to implement a single unit of behavior that is intended to pass to other code.
  • Its usable when just simple instance of functional interface is desired, without having a type, constructor and related stuff.
  • On the other hand anonymous inner classes are used when new fields and functionality is required.

Lambda expressions and Anonymous inner classes

  • Anonymous classes introduce next level of scoping, whereas lambda expression are just like an enclosing environment. New variables with same name as in their super scope are allowed in classes whereas lambdas throw error and don’t allow that. Because they doesn’t introduce next level of scoping, local variable and fields/methods are directly accessible from enclosing scope.
  • Anonymous classes resolves this keyword to their own object, though lambda resolves it to enclosing class where it’s written. To access variables inside lambda from enclosing class, you can use this.
  • However, like anonymous classes, lambda expressions can only access local variables of the enclosing block that are final or effectively final. Access to non-final variables throws an error just like anonymous classes.
  • Serialization of lambda expressions are allowed only if its parameters and return type/target type are Serializable. Whereas its serialization is highly discouraged like anonymous classes.
  • Lambda expressions are compiled as private methods of enclosing class. Internally invokedynamic is used to bind methods dynamically, that were introduced in java 7.

Source Code

An IntelliJ project containing the source files for the examples covered in the post.

source: http://zishanbilal.com/2014/05/08/java-8-lambda-expressions-examples/

Java 8 Lambda Expressions by Examples,布布扣,bubuko.com

Java 8 Lambda Expressions by Examples

上一篇:Java中的静态代理、通用动态代理类以及原理剖析


下一篇:java String转Integer分析