Introduction to the Use of Lambda Expressions

Written in front

This paper mainly introduces the use of Lambda expression and functional interface, and does not involve the principle. It is hoped that the beginners can flexibly use Lambda expression programming in daily development after reading it.

Characteristics of Lambda

Java 8 adds a completely new language-level feature called Lambda expressions. Allow us to pass functions as parameters to a method, or store code itself as data processing in variables

Lambda expression grammar

The Lambda expression consists of a list of parameters and a body of methods: `(type 1 arg1, type 2 arg2,...) - > {body;}; `The parameters are separated by `, `
  • 1. When there is no reference, use () empty brackets. For example: () - > {body};
  • 2. When there is only one entry, there are two ways to express it:

      1) (String s) -> {body};
      2) s - > {body}; omitting the parameter type, Lambda infers the parameter type from the context and does not need parentheses to surround it.
    
  • 3. When there are multiple parameters: (String name, int age, Boolean flag) - > {body}

       The parameter type can also be omitted and written directly as follows: `(name, age, flag) -> {body} `The parameter list must be surrounded by `()'.
  • 4. When there is only one statement in the method body, the {} can be omitted. For example: () - > System. out. println ("hello world");
 - Some examples:

1,()-> System.out.println("Lambda Expression");
2,(String s) -> System.out.println(s);
3,s -> return s;

4,(String s,int num) -> {
    if(num >= 10){
        return s.toUpperCase();
    }
    return s.toLowerCase();
};
5,(age,name,flag) -> 42;

Lambda expressions can't be used alone, they need to be bound to functional interfaces to be used.

Functional interface

Functional Interface is Java 8's term for a special type of interface. There are only one number of such interface abstraction methods, annotated with @Functional Interface. It should be noted that there is only one interface for abstract methods, and even without @Functional Interface annotations, the compiler will treat it as a functional interface.

In particular, the java.util.Comparator<T> interface has two abstract methods, as follows:

int compare(T o1, T o2);
boolean equals(Object obj);

But it's still a functional interface. Why?

If the interface declares an abstract method that covers the common method of java.lang.Object, the method will not be counted in the abstract method count of the interface, because any implementation of the interface will have an implementation for the method from java.lang.Object or elsewhere. The equals(Object obj) method in the java.util.Comparator < T> interface is a declaration of a public method in java.lang.Object, not in the count of abstract methods.

In fact, Lambda expression is the realization of the only abstract method in the functional interface, so the parameters of Lambda expression need to be consistent with the parameter list of the abstract method in the functional interface.

In jdk8, a new package java.util.function is introduced, and a series of functional interfaces are provided. The interfaces in this package can be roughly divided into the following four categories:
Function < T, R >: Receive parameters and return results, abstract method is R apply (T)
Consumer < T >: Receive parameters, no result is returned, the abstract method is void accept (T)
Supplier < T >: No parameter is received, but the result is returned. The abstract method is T get().
Predicate < T >: Receive parameters, return boolean value, abstract method is boolean test (T)

You can choose different functional interfaces according to your needs, and you don't need to use them every time you customize them.

Examples of Lambda Expressions and Functional Interfaces

1,Get the instance object of the functional interface and call the method

//Custom Functional Interface
@FunctionalInterface
public interface TestFunctionInterface {
    //The only abstract method of functional interfaces requires Lambda expression implementation
    String testFunction(String a,int b);
    
}

//Test class
public class Client {
    public static void main(String[] args) {
      //Implementing the abstract method of TestFunctionInterface with Lambda expression and obtaining the instance object
      TestFunctionInterface testFunctionInterface = (String name,int age)->{
      if(age==10){
          return name.toUpperCase();
      }
      return "NO NAME!";
    };

    //The testFunction() method is called by testFunctionInterface and the parameters are passed in to get the returned result.
    String result = testFunctionInterface.testFunction("David",10);
    System.out.println(result);

    }

}


//Print result: DAVID

----------
2,Functional interfaces are used as parameters of a method

//Custom Functional Interface
@FunctionalInterface
public interface TestFunctionInterface {
    //The only abstract method of functional interfaces requires Lambda expression implementation
    String testFunction(String a,int b);
    
}


//Test class
public class Client {
    public static void main(String[] args) {
        //Call the test method
        test("steven",20,(name,age) -> {
            if(age==10){
                return name.toUpperCase();
            }
            return "NO NAME!";
            }
        );

    }
    
    //A Method of Using Functional Interface Objects as Parameters
    public static void test(String name,int age,TestFunctionInterface testFunctionInterface){
        String result = testFunctionInterface.testFunction(name,age);
        System.out.println(result);
    }

}

//Print result: NO NAME!

Special note: When using Lambda expressions in the above two methods, the parameters and return values of Lambda must be consistent with the abstract method of functional interfaces.

Method reference

Lambda expressions use:: to call specific existing methods as the only abstract method implementation of a functional interface, making the code more readable

1. Static method

Lambda :(arg0,arg1,arg2,...) -> ClassName.staticMethod(arg0,arg1,arg2,...)
Method Reference: ClassName::staticMethod

` TestStaticMethod::testStaticMethod `is to call the static method `String testStaticMethod'(int age, Boolean flag)` as the implementation of functional interface Abstract method. The parameter type and return value of the method invoked need to be consistent with the abstract method.
@FunctionalInterface
public interface TestFunctionInterface {

    String testFunction(int i);

}

public class TestStaticMethod {
    public static String testStaticMethod(int age,boolean flag){
        if(age >10 && flag){
            return "SUCCESS";
        }

        return "ERROR";
    }
}


public class Client {
    public static void main(String[] args) {
        //TestStaticMethod::testStaticMethod is equivalent to Lambda expression: (int age, Boolean flag) - > TestStaticMethod. TestStaticMethod (age, flag); the parameters of Lambda are passed into the calling method sequentially, and type mismatch will result in an error.
        TestFunctionInterface testFunctionInterface = TestStaticMethod::testStaticMethod;
        String result = testFunctionInterface.testFuction(26,true);
        System.out.println(result);


    }

}


//Print result: SUCCESS

2. Reference to any type of instance method

Lambda:(arg0,arg1,arg2,...) -> arg0.instanceMethod(arg1,arg2,...)
Method Reference: ClassName. instance Method (Note: arg0 is an object of ClassName type)

/**
    1) Functional interface abstraction method has only one parameter
*/
@FunctionalInterface
public interface TestFunctionInterface {

    int testFuction(String s);

}


public class Client {
    public static void main(String[] args) {
        //Method reference: String::length is equivalent to Lambda expression: (arg0) - > arg0. Length()
        //In fact, the length() method of the parameter object arg0 is called as the method body of the abstract method, and the return value of arg0.length() is the return value of the abstract method. 
        TestFunctionInterface testFunctionInterface = String::length;
        System.out.println(testFunctionInterface.testFuction("king"));
    }

}

//Print results: 4

/**
    2) Functional interface abstraction method has multiple parameters
*/
@FunctionalInterface
public interface TestFunctionInterface {

    int testFuction(TestMethodRef testMethodRef, String name, int age);

}

public class TestMethodRef {
    public int testMethodRef(String name,int age){
        return name.length()+age;
    }
}

public class Client {
    public static void main(String[] args) {
        //TestMethodRef::testMethodRef is equivalent to (arg0, arg1, arg2) - > arg0. testMethodRef (arg1, arg2)
        //The compiler only calls the testMethodRef(arg1,arg2) method of the first parameter arg0, and passes the remaining arg1,arg2 into the method in the original order as parameters. Mismatch of type will cause errors.
        TestFunctionInterface testFunctionInterface = TestMethodRef::testMethodRef;
        int result = testFunctionInterface.testFuction(new TestMethodRef(),"king",12);
        System.out.println(result);

    }

}

//Print results: 16

3.Instance Method Reference to Existing Objects
@FunctionalInterface
public interface TestFunctionInterface {

    char testFuction(int index);

}

public class Client {
    public static void main(String[] args) {
        String content="hello";
        //content::charAt is equivalent to (int index) - > content. charAt (index);
        TestFunctionInterface testFunctionInterface = content::charAt;
        System.out.println(testFunctionInterface.testFuction(0));
    }

}    

//Print result:h

Stream API

The java.util.stream.Stream interface, like Lambda expressions, is a new introduction of Java 8. All Stream operations must take Lambda expressions as parameters. Stream (Stream) is a queue of elements from data sources and supports aggregation operations. It treats the set of elements processed as a stream, which is transmitted in pipelines and can be processed at pipeline nodes, such as filtering, sorting, aggregation, etc. Element flow is processed by intermediate operation in pipeline, and the result of the former is obtained by terminal operation. Here we briefly introduce the commonly used Stream API.

  • forEach provides iterative functionality for stream flow elements
public class Client {
    public static void main(String[] args) {

        List<Info> list = new ArrayList<>();
        list.add(new Info("first", 1));
        list.add(new Info("second", 2));
        list.add(new Info("third", 3));
        list.add(new Info("four", 4));
        list.add(new Info("five", 5));
        //list.stream() creates a Stream stream and calls forEast to print all name s
        list.stream().forEach(t->System.out.println(t.name));
    }

}
//Print results:
first
second
third
four
five
  • Filter sets filter limits

public class Client {
    public static void main(String[] args) {

        List<Info> list = new ArrayList<>();
        list.add(new Info("first", 1));
        list.add(new Info("second", 2));
        list.add(new Info("third", 3));
        list.add(new Info("four", 4));
        list.add(new Info("five", 5));
        //Filtering for age
        list.stream().filter(t->t.age>3).forEach(t->System.out.println(t.name));
    }

}


//Print results:
four
five
  • map maps flow elements to different results
public class Client {
    public static void main(String[] args) {
        List<Info> list = new ArrayList<>();
        list.add(new Info("first", 1));
        list.add(new Info("second", 2));
        list.add(new Info("third", 3));
        list.add(new Info("four", 4));
        list.add(new Info("five", 5));
        //Mapping Info objects to String objects
        List<String> names=list.stream().map(t->t.name).collect(Collectors.toList());
    }

}
  • limit Gets a specified number of stream elements
Stream.of(1,2,3,4,5,6,7).limit(3).forEach(System.out::println);
Print results:
1
2
3
  • skip ignores a specified number of stream elements
// Ignore the first four stream elements
Stream.of(1,2,3,4,5,6,7).skip(4).forEach(System.out::println);

Print results:
5
6
7
  • Sorted convection sorted
public class Client {
    public static void main(String[] args) {
        List<Info> list = new ArrayList<>();
        list.add(new Info("first", 1));
        list.add(new Info("second", 2));
        list.add(new Info("third", 3));
        list.add(new Info("four", 4));
        list.add(new Info("five", 5));
        list.stream().sorted(new Comparator<Info>() {
            @Override
            //In descending order according to age
            public int compare(Info o1, Info o2) {
                return o2.age-o1.age;
            }
        }).forEach(t->System.out.print(t.name+" "));
    }

}

//Print result: five four third second first 

  • findFirst returns the first element
//findFirst() returns the Optional object and needs to call the Optional.get() method to get the value
int value=Stream.of(1,2,3,4,5,6,7).findFirst().get();
System.out.println(value);

//Print results: 1
  • anyMatch matches any one and returns true
//As long as the value of one element in the stream stream stream equals 2, it returns true
boolean value=Stream.of(1,2,3,4,5,6,7).anyMatch(t->t==2);
System.out.println(value);

//Print results:
true
  • All Match matches all elements before returning true
//All elements in the stream stream stream have a value equal to 2 before returning true
boolean value=Stream.of(1,2,3,4,5,6,7).allMatch(t->t==2);
System.out.println(value);

//Print results:
false
  • collect converts Stream to a collection
List list=Stream.of(1,2,3,4,5,6,7).collect(Collectors.toList());
Set set = Stream.of(1,2,3,4,5,6,7).collect(Collectors.toSet());

Last

I hope you can use Lambda expression, functional interface and Stream API more in the development, which is really convenient and efficient.

Keywords: Java Lambda Programming

Added by ruiner17 on Thu, 26 Sep 2019 07:36:29 +0300