Since the release of Java 8 on March 18, 2014, Lambdas are now a familiar part of the Java environment. Brings the long-awaited feature of Lambda expressions (aka closures). They have had a greater impact on how we program in Java than any other change in the history of the platform.

What is a Lambda expression?

In mathematics and computation, a Lambda expression is usually a function: it specifies an output value for a combination of some or all input values. Lambda expressions in Java introduce the concept of functions into the language. In traditional Java terminology, Lambdas can be understood as an anonymous method with a more compact syntax that also allows the omission of modifiers, return types, and in some cases parameter types.

grammar

The basic syntax of Lambda is:

(parameters) -> expression
Copy the code

or

(parameters) -> { statements; }
Copy the code

example

/ / 1
(int x, int y) -> x + y                          // Take two integers and return their sum
/ / 2
(x, y) -> x - y                                  // Take two numbers and return their difference
/ / 3() - >42                                         // Accept no value and return 42
/ / 4
(String s) -> System.out.println(s)              // Take a string, print its value to the console, and return nothing
/ / 5
x -> 2 * x                                       // Take a number and return a double result
/ / 6
c -> { int s = c.size(); c.clear(); return s; }  // Get a collection, clear it, and return its previous size
Copy the code

notes

  • Parameter types can be explicitly declared (examples 1, 4) or implicitly inferred (examples 2, 5, 6). Declarative and inferred arguments cannot be mixed in a Lambda expression;

  • The body can be a block (enclosed in parentheses, example 6) or an expression (Example 1-5). The block can return a value (example 6), or it can return nothing. The rules for using or omitting the return keyword in a block are the same as those for a normal method body;

  • If the body is an expression, it may return a value (for example, 1, 2, 3, 5) or nothing (for example, 4);

  • Single inferred type arguments can omit parentheses (e.g., 5, 6);

  • The comment on example 6 should be understood to mean that Lambda can act on a collection. Again, depending on the context in which it appears, it can act on other types of objects with method sizes and clearings, as well as the appropriate parameters and return types.

Why were Lambda expressions added to Java?

In Java 8, the goal is to provide collections with methods that take functions and use them differently to process their elements. As an example, we’ll use a very simple method, forEach, that takes a function and applies it to each element. The benefit of this change is that collections can now organize their own iterations internally, shifting the responsibility for parallelization from client code to library code. However, for client code to take advantage of this, there needs to be an easy way to provide functions for collection methods. Currently, the standard way to do this is through anonymous classes with appropriate interfaces. However, the syntax used to define anonymous inner classes is too unwieldy for this purpose.

For example, the forEach method on the collection gets an instance of the consumer interface and calls its accept method forEach element:

interface Consumer<T> { void accept(T t); } 
Copy the code

Suppose we want to use forEach to transpose the X and y coordinates of each element in the java.awt.point list. Using an anonymous inner class to implement the consumer, we will pass in a transposition function like this:

pointList.forEach(new Consumer<Point>() { 
    public void accept(Point p) { p.move(p.y, p.x); }});Copy the code

However, the same effect can be achieved more precisely with Lambda:

pointList.forEach(p -> p.move(p.y, p.x)); 
Copy the code

So where can we use Lambda expressions?

Lambda expressions can be written in any context that has a target type:

  • Variable declarations, assignments, and array initializers whose target type is the type (or array type) assigned to;
  • A return statement whose target type is the return type of a method;
  • A method or constructor parameter whose target type is the type of the corresponding parameter. If a method or constructor is overloaded, the usual mechanism for overload resolution is used before the Lambda expression matches the target type. (After overload resolution, there may still be multiple matching methods or constructor signatures that accept different function interfaces of the same function type. In this case, the Lambda expression must be converted to the type of one of these functional interfaces);
  • Lambda expression body whose target type is the type expected by the body, which in turn is derived from the external target type:
Callable<Runnable> c = () -> () -> { System.out.println("hi"); };
Copy the code

The external target type here is Callable, which has a function type:

Runnable call(a) throws Exception;
Copy the code

Thus, the target type of the Lambda body is the function type of Runnable, the run method. It takes no arguments and does not return any values, so matches the internal Lambda above;

  • Ternary operators. Such as:
Callable<Integer> c = flag ? (() - >23) : (() - >.42);
Copy the code
  • Casts an expression that explicitly provides the target type. Such as:
Object o = () -> { System.out.println("hi"); };	             // Invalid: may be Runnable or Callable
Object o = (Runnable) () -> { System.out.println("hi"); };	  // legal: because it disambiguates
Copy the code

For more technical articles, please follow my official account:TomScript, get exclusive learning resources and daily dry goods push.

Original link:blog.sagowiec.com/article/3