Java8 introduces Lambda expressions, which allow developers to pass functions as arguments to a method or treat the code itself as data. Lambda expressions are used to make applications concise and compact. Many languages (Groovy, Scala, etc.) have supported Lambda expressions since their design. But Java uses anonymous inner classes instead. Finally, with the help of the powerful community, we found a compromise Lambda implementation scheme, which can achieve a concise and compact language structure.

The evolution of anonymous inner classes to Lambda

An anonymous inner class is a class without a name that exists inside a class or method. When we need to use a class only once to create and use a combination, we can choose the anonymous inner class, saving us the steps of defining the class.

An anonymous inner class inherits a class or implements an interface, or an anonymous object that subclasses the class or implements the interface. Let’s look at an example of an anonymous inner class

package com.java8;
/* Define and use anonymous inner classes */
public class NoNameClass {
   public static void main(String[] args) {

       Model m = new Model(){
           @Override
           public void func(a) {
               System.out.println("Method implementation"); }}; m.func(); }}// The interface to be implemented
interface Model{
   void func(a); } need more information + our programmer little sister v: lezijie00766, refused to add without remarks.)Copy the code

Equivalent Lambda code

package com.java8;
/* Define and use Lambda simplifications */
public class NoNameClass {
   public static void main(String[] args) {

       Model m = new Model(){()->{
           System.out.println("Method implementation"); }}; m.func(); }}Copy the code

As you can see, Lambda expressions are used instead of anonymous inner class code, making the code simpler and more compact.

Second, the grammar

(parameters) -> expression 或 (parameters) ->{ statements; }

  • Optional type declaration

    There is no need to declare parameter types, and the compiler can uniformly identify parameter values.

  • Optional parameter parentheses

    Parentheses are not required for one parameter, but parentheses are required for multiple parameters.

  • Optional braces

    If the body contains a statement, you do not need braces.

  • Optional return keyword

    If the body returns only one expression value, the compiler automatically returns the value. The braces need to indicate that the expression returns a numeric value.

Examples of Lambda expressions:

3. The form of Lambda

With Lambda, implementation methods can have arguments or return values, and if no argument type is specified, the compiler can infer that.

1. No parameter return value

Generates any integer between [1,10]

interface Model2{
   int func(a);
}
Model2 md2 = () -> {return (int)(Math.random()*10+1)};
Copy the code

Rewriting Lambda requires corresponding abstract methods, using () placeholders when there are no arguments, and omitting return and {} when the expression is a single line of code.

Lambda is equivalent to:

Model2 md2 = () -> (int)(Math.random()*10+1);
Copy the code

2. Parameter with return value

Returns a string that describes a number.

interface Model3{
   String func(int a);
}
Model3 md3 = (int a) -> {
   return "This is a number " + a;
};
Copy the code

The type of the parameter can be omitted, which is inferred by the compiler, and () can also be omitted.

Lambda is equivalent to:

md3 =  a -> "This is a number " + a;
Copy the code

Omit the argument type, the parenthesis, and the implementation body’s parenthesis and return.

3. Take multiple parameters

Computes the operation of two numbers based on the input operator and returns the result

interface Model4{
   String func(int a, int b, String oper);
}
Model4 md4 = (a, b, s) -> {
     String res = "";
     if("+".equals(s)){
           res = ( a+b ) + "";
    }else if("-".equals(s)){
           res = ( a-b ) + "";
    }else if("*".equals(s)){
           res = ( a*b ) + "";
    }else if("/".equals(s)){
           res = ( a/b ) + ""; // We can divide by 0
    }else{
           res =  "Error in operation.";
    }
     return res;
};
System.out.println(md4.func(1.1."+"));
Copy the code

The above example is a Lambda expression for multiple arguments, with the type of each argument omitted and the compiler automatically inferences. The {} of the implementation body cannot be omitted in multiple statements.

Lambda as a parameter

Prior to Java8, an interface could be passed in as a method parameter and must be executed with an instance of the interface implementation class. Starting with java8, lambdas can be implemented as interface methods and passed in as arguments, eliminating object creation in both form and reality. Make the code more compact, simple and efficient.

Defines the interface

In the interface, there must be one and only one abstract method to determine the Lambda template

// A method with no parameters and no return value
interface LambdaInterface1{
   void printString(a);
}
// A method with arguments that return no value
interface  LambdaInterface2{
   void printString(String str);
}
Copy the code

Define methods to receive parameters

You need an interface as an argument in a method

/ / no arguments
public static void testLambda(LambdaInterface1 lam1){
 lam1.printString();
}
/ / take ginseng
public static void testLambda2(String s,LambdaInterface2 lam2){
 lam2.printString(s);
}
Copy the code

Lambda expressions are passed in as arguments

// Lambda takes no arguments
testLambda(()->{
    System.out.println("It can be simple, it can be complicated.");
});
// Lambda as an argument
testLambdaParam("hello",(a)->{
    System.out.println(a);
});
Copy the code

5. Use variables in Lambda

You can define your own local variables in a Lambda, you can use local variables of an outer method, and you can use attributes. This is not hard to understand, since it is a method implementation, only write a block of code, so it is not excessive to use the local variables of the method itself and the class attributes.

public static void main(String[] args) {
    List<String> strs = new ArrayList<String>(){
        {
            add("aaa");
            add("bbb");
            add("ccc"); }};int j = 1;
    strs.forEach((str)->{
        int i = 0;
        System.out.println(str + "" + i + "" + j);
    });
}
Copy the code

Lambda type inference

Type checking

The type of Lambda is inferred from the context in which Lambda is used. The arguments to Lambda expressions correspond to the arguments and return value types of methods in functional interfaces. The type required by Lambda expressions, or the functional interface that Lambda implements, is called the target type.

Type inference

Use the target type to check whether a Lambda can be used in a particular context, and infer the type of Lambda parameters.

Lambda expression practice

1, hot commodity sequencing

Sorting for the development of long for you may not be strange, if the original you have done e-commerce projects, I believe that the e-commerce scene under the commodity record sorting operation is very emotional, we use Lambda to see the operation of hot commodity sorting.

Test data The following uses mobile phone test data as an example

/** * The actual development data is usually fetched from the database * test data is used here */
Goods g01=new Goods(1."Millet 9".1789.200, BigDecimal.valueOf(2500));
Goods g02=new Goods(2."Huawei Mate20".5000.3000, BigDecimal.valueOf(7000));
Goods g03=new Goods(3."OPPO R17".2000.2827, BigDecimal.valueOf(1500));
Goods g04=new Goods(4."The meizu Note9." ".2000.1600, BigDecimal.valueOf(1600));
Goods g05=new Goods(5."One plus 6 t".8000.5000, BigDecimal.valueOf(3500));
List<Goods> goods= Arrays.asList(g01,g02,g03,g04,g05);
Copy the code

The collections.sort static method implements sorting

Collections.sort(goods,(g1,g2)->g1.getSale()-g2.getSale());
Copy the code

The list.sort default method implements collection sorting

// Use Lambda to sort the item records by volume
goods.sort((g1,g2)->g1.getSale()-g2.getSale());
Copy the code

The stream. sorted method implements element sorting

// Multi-condition sort Lambda configuration Stream sales + price sort if sales are equal, sort by price
goods =goods.stream().sorted((g1,g2)->g1.getSale()-g2.getSale())
.sorted((g1,g2)->g1.getPrice().compareTo(g2.getPrice()))
.collect(Collectors.toList());
Copy the code

2. Log output optimization

For project development log printing is an unattainable module, whether in the development stage or after the project deployment online, the output of log information is an important reference index for developers and operation and maintenance personnel.

Log output scenario The user module UserService is used as an example. The log output code before optimization is as follows:

public String login(String userName, String userPwd) {
    logger.info("UserService receives parameter -->" + userName + "," + userPwd);
    /** * Logins omit */
    return "login";
}
Copy the code

Set the log level to DEBUG to view parameters received by the backend during development. When the log level is set to INFO, the debug log should not be output. In addition, when the debug method is called, the string parameters passed in need to be concatenated. The situation can get worse when accessing the mall project activity: all debug messages are printed out with a lot of string concatenation, which affects the performance of the entire application.

Log output Scenario This section uses the user module UserService as an example. The log output code is optimized

  • Determine the log output level before output logs
  • Delay log content output with Lambda
/** * Add info method * Determine the log printing level * Output log information when the condition is true *@param logger
* @param message
*/
public void info(Log logger, Supplier<String> message){
   if(logger.isInfoEnabled()){ logger.info(message.get()); }}public String login(String userName, String userPwd) {
   //logger.info(" + userName + "," + userPwd);
   // Delay Lambda expression execution only with certainty
   info(logger,()->"UserService receives parameter -->" + userName + "," + userPwd);
   return "login";
}
Copy the code

Advantages and usage scenarios of Lambda

The introduction of Lambda expressions replaces anonymous inner classes, making code concise and compact, while the inertness of Lambda improves application performance at development time.

For Lambda application scenarios, the code structure is usually combined with functional interfaces to make the development of functional oriented programming, which is also a new idea introduced in Java8 – functional programming (described later). At the same time, it will be combined with the interface default method mentioned earlier to withdraw into the application development.

–>” + userName + “,” + userPwd); // Delay Lambda expression execution only if info(Logger,()->”UserService receives arguments –>” + userName + “,” + userPwd); return “login”; }

The introduction of Lambda expressions has replaced anonymous inner classes, making the code concise and compact. At the same time, the inertness of Lambda can improve the performance of applications at the time of development. For Lambda application scenarios, the code structure is usually combined with functional interfaces to make the development of functional oriented programming, which is also a new idea introduced in Java8 - functional programming (described later). At the same time, it will be combined with the interface default method mentioned earlier to withdraw into the application development.Copy the code