Java 8 lambda expressions: how to use, examples

Every developer should learn to use new programming features, especially now that the 8th version has reached its peak usage. Lambda expressions are a new and important feature included in Java 8. It provides a clear and concise way of presenting a method that improves Collection libraries by simplifying iteration, filtering, and data retrieval. New concurrency features improve performance in multi-core environments.

The principle of lambda expressions

Several years ago, experts discussed Java language extensions for functional programming. In 2009, it became clear that Java without lambdas would look outdated compared to other programming languages, since modern multiprocessor and multi-core hardware requires simple support for parallelizing programs. That's why lambda expressions are needed.

In Java, all collections have a forEach method that inherits from its Iterable super-interface. It has existed since Java 5, has been expanded to version 8. The forEach method iterates over all elements of the collection and applies a function to each element.

A lambda expression is an anonymous function that provides parameterization of behavior. It consists of a list of return parameters and exceptions that are selected. A Java lambda expression instance can be assigned to any Iterable matching the definition, provided that it is functional.

Important points for understanding the lambda expression:

  1. The element to the left of the arrow (->) is the lambda parameters. In this case, the input parameter is defined as String param.
  2. To the right of the arrow (->) is the lambda body.
  3. The body is the place where the lambda is actually processed, that is, it determines its logic. Usually, a Java lambda expression has simple logic.
Plain lambda Java expressions




Syntax options for parameter list

There are several syntax options for the parameter list. Here is a simplified version of the syntax of a lambda expression:





  1. LambdaExpression.
  2. LambdaParameters '->' LambdaBody LambdaParameters.
  3. Identifier '(' ParameterList ')' LambdaBody.
  4. Expression Block.

The parameter list is either a comma-separated list in parentheses or a single identifier without parentheses. If you use a parenthesized list, you need to decide whether the parameter type will be registered for everyone or if it will not be specified, then it will be automatically determined by the compiler. Here are some examples of Java lambda expressions:

(int x) -> x + 1

List of parameters with a single parameter with explicit type specification

int x -> x + 1

Incorrect if parameter type is specified, parentheses are used

(x) -> x + 1

A list of parameters with a single parameter without an explicit type specification, the compiler deduces the missing parameter type from the context

x -> x + 1

A list of parameters with a single parameter without an explicit type specification. In this case, parentheses are omitted.

(int x, int y) -> x + y

List of parameters with two parameters n with explicit type specification

int x, int y -> x + y

Incorrect if parameter type is specified, then parentheses should be used

(x, y) -> x + y

A list of parameters with two parameters without an explicit type specification

x, y -> x + y

Incorrect, brackets must be used for more than one parameter

(x, int y) -> x + y

False, you cannot mix parameters with and without a type. Either everyone has an explicit type specification, or not

() -> 42

The list may be empty.

The body of a lambda is either a single expression or a list of expressions in parentheses. Here are some examples of Java lambda expressions:

() -> System.gc ()

Solitary expression body

(String [] args)

-> (args! = null)? args.length: 0

The operator also returns a single expression.

(String [] args)

-> {if (args! = null)

return args.length;

yet

return 0;

}

Curly braces are used here because it is an instruction, not an expression

(int x) -> x + 1

The body when transmitting lambda expressions.

(int x) -> return x + 1

False, statement starts with return, and there is no lambda, return must end with a semicolon and be in brackets

(int x) -> {return x + 1; }

Right

The expression is displayed only in the source code at points where there is an output context that the compiler can solve. Therefore, lambda is allowed only in the following places:

  • On the right side of the assignments;
  • as arguments to a method when invoked;
  • as a value in a return statement;
  • in whole value.

Functional Interfaces

Functional Interfaces




The 8th version brought a powerful syntactic improvement in the form of expressions. Previously, they usually created a class for each case when it was necessary to encapsulate a single functionality.

For all functional interfaces, it is recommended to have an informative annotation. This not only clearly conveys its purpose, but also allows the compiler to generate an error if the annotated interface does not meet the SAM conditions. The interface with the Single Abstract Method is functional, and its implementation can be considered before using lambda expressions in Java 8.





Methods are not initially abstract or considered, and the interface may still have several default methods. You can observe this by looking at the Function documentation. The simplest and most common case of lambda is a functional interface with a method that gets one value, returning another. This function of a single argument is represented by the Function interface, which is parameterized by the types of arguments and return values. Java Expression Lambda Examples:

  • one;
  • public interface Function {...}.

Anonymous inner class

In Java, anonymous inner classes provide a way to implement classes that occur only once in an application. For example, a standard Swing or JavaFX application requires several keyboard and mouse event handlers. Instead of writing a separate class for each event, write a common command. Creating a class where it is needed makes code much easier to read.

Class in place




It is impossible to correctly understand what lambda expressions are without considering functional interfaces. Using them with anonymous inner classes is a common pattern in Java. In addition to the EventListener classes, interfaces such as Runnable, Comparator are used in a similar way. Therefore, functional interfaces are used specifically with lambda expressions.

Functional Interfaces




Anonymous Function Expression

Basically, Lambda Expression is a brief introduction to an anonymous function that can be passed. Thus, it has the following properties:

Anonymous Function Expression




  1. Anonymity, because she does not have, as usual, an explicit name.
  2. Functionality, it can be considered as a function, because lambda is not associated with a particular class, like a method. But similarly to the method, a lambda has a list of parameters, a body, a return type, and a list of exceptions that can be thrown.
  3. Pass, lambda expression can be passed as an argument to a method or stored in a variable.
  4. For brevity, you do not need to write a lot of templates, as for anonymous classes. Technically, Lambda expressions allow you to do what you did not do before Java 8, and now you don’t need to write awkward code to use parameterization of behavior.
  5. List of parameters. In this case, it reflects the parameters of the comparator comparison method - two Apple objects.
  6. The arrow “->” separates the parameter list from the lambda body.
  7. An expression is considered the return value of a lambda.

Expression syntax

Lambda expressions define the bulk of anonymous inner classes by converting 5 lines of code into a single statement. This simple horizontal solution solves the "vertical problem" represented by inner classes. Lambda expression consists of 3 parts.

Expression syntax




A body can be either a single expression or an operator block. In the form of expression, the body is simply evaluated and returned. In block form, the body is evaluated as the body of the method, and the return statement returns control to the caller of the anonymous method. At the top level, break continue, keywords are illegal but allowed inside loops. If the body produces a result, each control path must return something or throw an exception.

For instance:

  • (int x, int y) -> x + y;
  • () -> 42;
  • (String s) -> {System.out.println (s); }.

The first expression takes two integer arguments, named x and y, and uses the form of the expression to return x + y. The second takes no arguments and uses the form to return the integer 42. The third expression takes the string and uses the form of the block to print the string to the console and returns nothing.

Protecting Object Variables from Mutation

Accessing a variable in lambda expressions will result in a compile-time error. But this does not mean that the user should mark each target variable as final. In accordance with the concept of “virtually final”, the compiler treats each variable as final if it is assigned only once.

It is safe to use such variables inside lambdas, because the compiler will monitor its state and throw a compile-time error right after any attempt to change them. This approach should simplify the lambda execution process. One of the main goals of lambda is to use it in parallel computing - this means that they are really useful when it comes to thread safety.

An effective final paradigm helps in many, but not every case. Lambdas cannot change the value of an object from the scope. But in the case of mutable object variables, the state can be changed inside lambda expressions. This code is legal because the full variable remains, in fact, final.

Capture instance variable

A lambda expression can also capture an instance variable in an object that creates a lambda. Here is an example that shows the process.

Capture instance variable




You need to pay attention to the link this.name inside the lambda body. This captures the name variable of the instance of the EventConsumerImpl object. You can even change the value of an instance variable after it is captured, and the value will be reflected inside the lambda. This semantics is actually one of the areas where Java lambdas differs from anonymous interface implementations. An anonymous interface implementation may have its own instance variables referenced by this link. However, a lambda cannot have its own instance variables, so this always points to an enclosing object.

Capturing a Static Variable A Java iamba expression can also capture static variables. This is not surprising since static variables are available wherever there is a Java application. The value of a static variable can also change after the lambda has captured it. The class is primarily used to show that lambda can access static variables.

Method Links

In the case when all lambda expressions make references to methods, you need to call another method with parameters passed to lambda, the Java lambda implementation provides a shorter way to express a method call. Here is an example of one functional interface

Method references like Lambdas




Since the body of a lambda consists of only one statement, you can actually omit the enclosed {} brackets. In addition, since there is only one parameter for this method, you can omit the enclosed () brackets around the parameter. Here's what the final lambda statement looks like: MyPrinter myPrinter = s -> System.out.println (s);

Since the whole lambda body does, passes the string parameter to the System.out.println () method, you can replace the above lambda declaration with a method reference.

Here's what the link to the lambda method looks like: MyPrinter myPrinter = System.out :: println.

You need to pay special attention to double colons ::. This signal to the Java compiler is a reference to a method. The specified method is what happens after double colons. Regardless of the class or object that owns the reference method.

Common Use Cases

Running lambda

Running lambda




In both cases, the parameter is not passed and returned. Runnable lambda - an expression that uses the block format, converts five lines of code in one instruction.

Lambda receiver.

Lambda receiver.




The lambda expression is passed as a parameter. Target typing is used in a number of contexts, including the following:

  1. Variable declarations.
  2. Assignment of return statements.
  3. Array initializers.
  4. Arguments of a method or constructor.
  5. Lambda expressions.
  6. Conditional expressions.
  7. Expression comparator lambda In Java.

The comparator class is used to sort collections. The following example sorts an ArrayList of Person objects based on surName. The following are the fields included in the Person class. Lambda supports “target typing,” which indicates the type of an object from the context in which it is used. Since a Comparator result is assigned to a specific one using generic, the compiler can conclude that both parameters are of Person type.

Comparator class




Guidelines for Providing Target Types

The method is general and abstract, which makes it easy to adapt to almost any lambda. Developers should learn this package before creating new interfaces. You can download lambda expressions in Java 8 pdf on the Internet.

In some UseFoo class, it takes this interface as a parameter. If you look at the expression more closely, you can see that Foo is nothing more than a function that takes one argument and gives the result. The 8th version already provides such an interface in function. You can completely remove the Foo interface and change the code by writing expressions.

Lambda expression approach




The lambda expression approach can be used for any suitable interface from old libraries. It can be used for interfaces such as Runnable, Comparator, and others. However, this does not mean that the user should review the older code base and change everything.

It is recommended to avoid overload methods with functional interfaces as parameters, and use them with different names in order to avoid collisions. Also, do not treat lambda expressions as inner classes, since it creates a new scope. You can overwrite local variables from the scope by creating new local variables with the same name and use the this keyword inside the class as a reference to the instance.

However, lambda expressions work with the enclosing region and you cannot overwrite variables from the enclosing region inside the lambda body. In this case, the keyword is a reference to the enclosing instance.

Lambda expressions are made short and clear, it is advisable to use a single line construction instead of a large block of code. Keep in mind that lambda should be an expression, not a narrative. Despite the concise syntax of these expressions, they must accurately express the functionality they provide. This is basically stylistic advice that does not affect performance.

However, the user should not use this “one-line lambda” rule as a dogma. If it has two or three lines in a lambda definition, it may not be practical to cast them to a single line. And you must also avoid specifying parameter types. In most cases, the compiler is able to resolve the type of lambda parameters using type inference, so adding a type to parameters is optional and can be omitted.

Lambda syntax requires brackets only around more than one parameter or in the absence of any parameter. That's why it's safe to make the code a little shorter and exclude parentheses when there is only one parameter. Such guidelines for writing Java lambda expressions for dummies can be found on the Internet.

Bracket and return operations are optional on single-line lambda bodies. This means that they can be omitted for clarity and brevity. Very often, lambda expressions simply invoke methods that are already implemented elsewhere. In this situation, it is very useful to use another function - method references. This is not always shorter, but makes the code more readable.

Lambda expressions work fine only with the functional interfaces of Java 8. You cannot use lambda expressions with an interface with more than one abstract method. To work with similar expressions, you need to make sure that the user has the eighth version of Java installed. Lambda expressions do not work on Java 7 and earlier.




All Articles