Java 8: Lambda Functions—Usage and Examples

DZone's Guide to

Java 8: Lambda Functions—Usage and Examples

One of the major new language features in Java 8 is the lambda function. In fact, it is one of the biggest changes since the Java 1 release. Take a look at this introduction to Java 8's lambda function.

One of the major new language features in Java 8 is the lambda function. In fact, it is one of the biggest changes since the Java 1 release. Lambdas are widely used in the programming language world, including the languages that compile to the Java platform. For instance, Groovy compiles to the Java platform and has very good support for lambda functions (also known as closures). Oracle decided to bring lambdas to the mainstream language on the JVM—the Java language itself—with Java 8.

Lambda Function Related Changes in Java 8

The introduction of lambdas required coordinated changes in the language, library, and the VM implementation:

The arrow operator (“->”) for defining lambda functions, the double colon operator (“::”) used for method references, and the default keyword.

The streams library and the integration of the collections library with streams.

Lambda functions are implemented using the invokedynamic instruction introduced in Java 7.

To support the introduction of lambdas into the language, the type inference has also been strengthened in Java 8. Lambdas enabled library writers to create parallel algorithms in the library to exploit inherent parallelism in the modern hardware (i.e., multi-cores).

In Java 8, java.util has been considerably enhanced using lambda functions. Java 8 has added two new packages: java.util.function and java.util.streams.

Lambdas can significantly change the way you design and write code. Why? Lambdas support the functional programming paradigm—that means learning and using lambdas would mean a paradigm shift for you. But you don’t need to worry about making a major shift—Java seamlessly integrates functional capabilities with the existing object-oriented features, and you can gradually shift to using more and more functional features in your programs.

Lambda Functions: Syntax

A lambda function consists of optional parameters, the arrow token, and the body:

LambdaParameters -> LambdaBody

LambdaParameters are parameters to the lambda function passed within opening parenthesis "(" and closing parenthesis ")". When more than one parameter is passed, they are separated by commas.

To support lambdas, Java has introduced a new operator “->”, also known as lambda operator or arrow operator. This arrow operator is required because we need to syntactically separate the parameter from the body.

LambdaBody can be an expression or a block. The body could consist of single statement (in that case no explicit curly braces defining a block are required); such a lambda body is known as an "expression lambda." If there are many statements in a lambda body, they need to be in a block of code; such a lambda body is known as "block lambda."

The compiler performs type inference for lambda expressions:

The compiler infers the types of the parameters if you do not specify the parameter types in a lambda function definition. When you specify the type of parameters, you need to either specify all or none, or else you will get a compiler error.

You can omit the parenthesis if there is only one parameter. But in this case, you cannot provide the type explicitly. You should leave it to the compiler to infer the type of that single parameter.

The return type of the lambda function is inferred from the body. If any of the code in the lambda returns a value, then all the paths should return a value, or else you will get a compiler error.

Some examples of valid lambda expressions (assuming that relevant functional interfaces are available):

-> 7
// if there are no parameters, then empty parentheses () must be provided
(arg1, int arg2) -> arg1 / arg2
// if argument types are provided, then it should be provided for all arguments or none of them

Lambda Function—An Example

Let us get started with a simple “hello world” example for lambda functions:

In this program, the interface LambdaFunction declares an abstract method named call(); hence it is a functional interface. Inside the main method in the FirstLambda class, a lambda function is assigned to a variable of the functional interface type LambdaFunction.

The statement System.out.println("Hello world") is the body of the lambda expression.

How does the lambda expression relate to the functional interface LambdaFunction? It is through the single abstract method inside the LambdaFunction interface: void call(). The signature of this abstract method and the lambda expression must match:

The lambda expression has () indicating it has no parameters—it matches with the call method that takes no parameters.

The statement System.out.println("Hello world") is the body of the lambda expression. This body serves as an implementation of the lambda function.

There is no return statement in this lambda expression body and hence the compiler infers the return type of this expression as the void type—that matches with the return type of the call method.

The next statement lambdaFunction.call(); invokes the lambda function. As a result of this function call, “Hello world” is printed on the console. Check out this book for more learning about Lambda Functions. You can download the source code here.