[Java] Functional Programming and Lambda Expression

Functional Programming and Lambda Expression

Advantages of 1 Functional Programming

1.1 Functional Programming Ideas

In mathematics, a function is a set of calculation schemes with inputs and outputs, that is, "What to do with something?" (What to do with something?) (What to do with something?) (What to do with something?) Functions in programming have similar concepts. When you call me, give me arguments to assign values to parameters, and then run the body of the method to return you a result. For callers, focus on what this method does. Relatively, object-oriented places too much emphasis on "must do things in the form of objects", while functional thinking tries to ignore the complex object-oriented syntax, which emphasizes what to do rather than what to do in the form.

  • Object-oriented thinking:

    • Do one thing, find an object that can solve it, call the method of the object, and finish the thing.
  • Functional programming ideas:

    • As long as the result can be obtained, it does not matter who does it, what is important is the result, and what is not the process.

After Java 8 introduced Lambda expressions, Java also began to support functional programming.

Lambda expressions are not the earliest used in Java and are supported in many languages, such as C++, C#, Python, Scala, and so on. If you have a Python or Javascript language base, it will be very helpful to understand Lambda expressions. In other words, lambda expressions are grammatical sugars that implement SAM interfaces, making Java a language that supports functional programming. Lambda's good writing greatly reduces code redundancy, as well as readability over redundant anonymous internal classes.

Note: "Grammatical sugar" refers to code grammar that is more convenient to use but does not change in principle. For example, the for-each syntax used when traversing a set is
The underlying implementation principle is still iterator, which is grammatical sugar. On an application level, Lambda in Java can be considered anonymous internals
Class "grammatical sugar", but they are different in principle.

Scanning VX for Java, Front End, Testing, python, etc.

1,2 Redundant Anonymous Internal Classes

When a thread needs to be started to complete a task, it usually takes place in java. The lang.Runnable interface defines the task content and uses java. The lang.Thread class to start the thread. The code is as follows:

 Copy code-behind code
public class Demo01 {
    public static void main(String[] args) {
        Runnable runnable = new Runnable() {
            @Override
            public void run() {// Override override abstract methods
                System.out.println("Override with anonymous internal class run Method");
            }
        };
        new Thread(runnable).start(); // Start Thread
        new Thread(new Runnable() {
            @Override
            public void run() {
                System.out.println("Do not create object overrides using anonymous internal classes run Method");
            }
        }).start();
    }
}

With the idea of "Everything is Object", this is justifiable: first create an anonymous internal class object for the Runnable interface to specify the task content, and then hand it over to a thread to start.

Code Analysis:

For Runnable's anonymous internal class usage, there are a few things you can analyze:

  • The Thread class requires the Runnable interface as a parameter, and the abstract run method is the core of the thread task content specified.
  • In order to specify the body of run's method, the implementation class of the Runnable interface has to be required.
  • To avoid the hassle of defining a RunnableImpl implementation class, you have to use an anonymous internal class;
  • The override of the abstract run method must be overridden, so the method name, method parameters, method return values must be rewritten and cannot be written incorrectly.
  • In fact, it seems that only the method body is the key.

1.3 Conversion of Programming Ideas

What to do, not who to do it, how to do it

Do we really want to create an anonymous internal class object? No We just have to create an object to do this. What we really want to do is pass code from the run method body to the Thread class.

Pass a piece of code - that's what we really want. Creating objects is only a means that has to be taken because of the object-oriented syntax. So, is there a simpler way? If we return our focus from how to do to what is essentially what to do, we will find that process and form are not really important as long as we can achieve our goals better.

Examples of life:

When we need to go from Beijing to Shanghai, we can choose high-speed rail, car, bike or hiking. Our real goal is to get to Shanghai, and how we get there doesn't matter, so we've been exploring whether there's a better way than high-speed rail - by airplane.

Now this kind of airplane (or even a spaceship) has been born: Oracle's Java 8 (JDK 1.8) in March 2014 added the new weight feature of Lambda expression, opening the door to a new world.

1.4 Experience Lambda's Better Writing

With the new Java 8 syntax, the anonymous internal class notation of the above Runnable interface can be equivalent through simpler Lambda expressions:

 Copy code-behind code
public class Demo01 {
    public static void main(String[] args) {
        new Thread(() -> {
            System.out.println("Use Lambda Expression override run Method");
        }).start();

        new Thread(() -> System.out.println("Use simplified Lambda Expression override run Method")).start();
    }
}

This code is exactly the same as what was just executed and can be passed at a compilation level of 1.8 or higher. You can see from the semantics of the code that we started a thread, and the content of the thread task was specified in a more concise form.

There is no longer the constraint of having to create interface objects and the burden of overriding overrides with abstract methods. It's that simple!

2 Functional Interface

The lambda expression is actually a statement that implements the SAM interface, which is called Single Abstract Method, that is, there is only one abstract method in the interface that needs to be implemented, although the interface can contain other non-abstract methods.

In fact, Lambda expressions can be used whenever an interface that meets the SAM characteristics can be called a functional interface, but to be clearer, it is better to declare the interface with @FunctionalInterface. Once the annotation is used to define the interface, the compiler will force a check that the interface does have and only has one abstract method, otherwise an error will be reported.

In previous SAM interfaces, the functional interfaces marked @FunctionalInterface were Runnable, Comparator, FileFilter.

Java8 is in java.util.function has added many new functional interfaces: mainly divided into four categories, consumption, supply, judgment and function. Basic to meet our development needs. Of course, you can also define your own functional interface.

2.1 Custom Functional Interface

Just make sure there is only one abstract method in the interface:

 Copy code-behind code
 Modifier interface Interface Name {
    public abstract Return value type method name(Optional parameter information);
    // Other non-abstract method content
}

public abstract of abstract methods in interfaces can be omitted

For example, declare a calculator Calculator interface that contains an abstract method, calc, that calculates two ints and returns the result:

 Copy code-behind code
public interface Calculator {
    int calc(int a, int b);
}

In the test class, declare one of the following methods:

 Copy code-behind code
public static void invokeCalc(int a, int b, Calculator calculator) {
    int result = calculator.calc(a, b);
    System.out.println("The result is:" + result);
}

The following tests are performed:

 Copy code-behind code
public static void main(String[] args) {
    invokeCalc(1, 2, (int a,int b)-> {return a+b;});
    invokeCalc(1, 2, (int a,int b)-> {return a-b;});
    invokeCalc(1, 2, (int a,int b)-> {return a*b;});
    invokeCalc(1, 2, (int a,int b)-> {return a/b;});
    invokeCalc(1, 2, (int a,int b)-> {return a%b;});
    invokeCalc(1, 2, (int a,int b)-> {return a>b?a:b;});
}

Classification of 2.2 Functional Interfaces

In addition to the functional interfaces that we can customize, jdk also gives us some built-in functional interfaces, categorized as follows

2.2. 1 Consumer Interface

Abstract method features of consumer interfaces: formal parameters, but return value type is void

Interface nameAbstract methoddescribe
Consumer<T>void accept(T t)Receive an object to complete a function
BiConsumer<T,U>void accept(T t, U u)Receive two objects to complete the function
DoubleConsumervoid accept(double value)Receive a double value
IntConsumervoid accept(int value)Receive an int value
LongConsumervoid accept(long value)Receive a long value
ObjDoubleConsumer<T>void accept(T t, double value)Receive an object and a double value
ObjIntConsumer<T>void accept(T t, int value)Receive an object and an int value
ObjLongConsumer<T>void accept(T t, long value)Receive an object and a long value

2.2. 2 Supply Interface

The abstract method features of this type of interface: no parameters, but return values

Interface nameAbstract methoddescribe
Supplier<T>T get()Return an object
BooleanSupplierboolean getAsBoolean()Returns a boolean value
DoubleSupplierdouble getAsDouble()Returns a double value
IntSupplierint getAsInt()Returns an int value
LongSupplierlong getAsLong()Returns a long value

2.2. 3 Assertive Interface

The abstract method feature of the interface here is that it has parameters, but the return value type is a boolean result.

Interface nameAbstract methoddescribe
Predicate<T>boolean test(T t)Receive an object
BiPredicate<T,U>boolean test(T t, U u)Receive two objects
DoublePredicateboolean test(double value)Receive a double value
IntPredicateboolean test(int value)Receive an int value
LongPredicateboolean test(long value)Receive a long value

2.2. 4 Functional Interface

The abstract method features of this type of interface: both parameters and return values

Interface nameAbstract methoddescribe
Function<T,R>R apply(T t)Receives a T-type object and returns an R-type object result
UnaryOperator<T>T apply(T t)Receives a T-type object and returns a T-type object result
DoubleFunction<R>R apply(double value)Receives a double value and returns an object of type R
IntFunction<R>R apply(int value)Receives an int value and returns an object of type R
LongFunction<R>R apply(long value)Receive a long value and return an object of type R
ToDoubleFunction<T>double applyAsDouble(T value)Receive a T-type object and return a double
ToIntFunction<T>int applyAsInt(T value)Receives a T-type object and returns an int
ToLongFunction<T>long applyAsLong(T value)Receive a T-type object and return a long
DoubleToIntFunctionint applyAsInt(double value)Receives a double value and returns an int result
DoubleToLongFunctionlong applyAsLong(double value)Receive a double value and return a long result
IntToDoubleFunctiondouble applyAsDouble(int value)Receives an int value and returns a double result
IntToLongFunctionlong applyAsLong(int value)Receive an int value and return a long result
LongToDoubleFunctiondouble applyAsDouble(long value)Receive a long value and return a double result
LongToIntFunctionint applyAsInt(long value)Receives a long value and returns an int result
DoubleUnaryOperatordouble applyAsDouble(double operand)Receive a double value and return a double
IntUnaryOperatorint applyAsInt(int operand)Receives an int value and returns an int result
LongUnaryOperatorlong applyAsLong(long operand)Receive a long value and return a long result
BiFunction<T,U,R>R apply(T t, U u)Receives a T-type and a U-type object and returns an R-type object result
BinaryOperator<T>T apply(T t, T u)Receives two T-type objects and returns a T-type object result
ToDoubleBiFunction<T,U>double applyAsDouble(T t, U u)Receives a T-type and a U-type object and returns a double
ToIntBiFunction<T,U>int applyAsInt(T t, U u)Receives a T-type and a U-type object and returns an int
ToLongBiFunction<T,U>long applyAsLong(T t, U u)Receives a T-type and a U-type object and returns a long
DoubleBinaryOperatordouble applyAsDouble(double left, double right)Receives two double values and returns a double result
IntBinaryOperatorint applyAsInt(int left, int right)Receives two ints and returns an int result
LongBinaryOperatorlong applyAsLong(long left, long right)Receives two long values and returns a long result

3 Lambda expression syntax

Lambda expressions are used to assign values to variables or parameters of [functional interfaces].

Essentially, Lambda expressions are "abstract methods" used to implement [functional interfaces]

Lambda expression syntax format

 Copy code-behind code
(parameter list) -> {Lambda body}

Explain:

  • (parameter list) It is the abstract method of the functional interface you want to assign (parameter list), refer to
  • {Lambda body} is the body of the method that implements this abstract method
  • ->Called the Lambda operator (there must be no space between the minus sign and the greater sign, and it must be a half-corner input in English)

Optimize: Lambda expressions can be streamlined

  • When there is only one sentence in {Lambda body}, you can omit {} and {;}
  • When there is only one sentence in the {Lambda body} and the statement is still a return statement, return can also be omitted, but if it is {;} Return cannot be omitted without omitting
  • The type of (parameter list) can be omitted
  • When there is only one parameter in the list, the data type can be omitted with (), but the parameter name cannot be omitted.
  • When (parameter list) is empty, () cannot be omitted

Sample code:

ps: The following demo uses Junit for unit testing, so if you don't understand it, you can learn it first Junit

 Copy code-behind code
public class TestLambdaGrammer {
        @Test
        public void test1(){
                //Apply Lambda expression to parameter or variable of Runnable interface
                /*
                 * There are two things you can do to write a lambda expression
                 * (1)Does the abstract method of this interface require an incoming parameter
                 *                 public void run()
                 * (2)What will the implementation of this abstract method do?
                 *                 For example: I want to print "hello lambda"
                 */
                Runnable r = () -> {System.out.println("hello lambda");};
        //Simplify, omit {;}
        Runnable r = () -> System.out.println("hello lambda");
        }

        @Test
        public void test2(){
                String[] arr = {"hello","Hello","java","chai"};

                //Sort arr arrays, but want to be case insensitive
                /*
                 * public static <T> void sort(T[] a,Comparator<? super T> c)
                 * Lambda expression is used here to assign values to parameters of type Comparator
                 * 
                 * Two things:
                 * (1)Abstract method of this interface: int compare(T o1, T o2)
                 * (2)What does this abstract method do?
                 *                 For example, here we want to make case-insensitive comparisons for elements of type String
                 */
                Arrays.sort(arr, (String o1, String o2) -> {return o1.compareToIgnoreCase(o2);});

                //{return;} was omitted
                //Arrays.sort(arr, (String o1, String o2) ->  o1.compareToIgnoreCase(o2));

                //Two String s were omitted
                Arrays.sort(arr, (o1, o2) ->  o1.compareToIgnoreCase(o2));
                //Print arr
                for (String string : arr) {
                        System.out.println(string);
                }
        }

        @Test
        public void test3(){
                ArrayList<String> list = new ArrayList<>();
                list.add("hello");
                list.add("java");
                list.add("world");

                /*
                 * JDK1.8 A default method has been added to the Collection of Collections, precisely in the Iterable interface
                 *                 default void forEach(Consumer<? super T> action) 
                 * This method is used to traverse collections, etc. Instead of the original foreach loop.
                 * 
                 * The parameter to this method is the Consumer interface type, which represents the consumer interface in a functional interface
                 * Now call this method, and you want to use the Lambda expression to assign a value to the Consumer interface type parameter
                 * 
                 * Two things:
                 * (1)Its Abstract method: void accept(T)
                 * (2)What is the accomplishment of an abstract method
                 *                 For example, to print this t here
                 */
//                list.forEach((String t) -> {System.out.println(t);});

                //Omit {;}
//                list.forEach((String t) -> System.out.println(t));

                //Omit String
//                list.forEach((t) -> System.out.println(t));

                //Omitted ()
                list.forEach(t -> System.out.println(t));
        }
}

Scanning VX for Java, Front End, Testing, python, etc.

4 Lambda Expression Practice

4.1 Use of consumer interface

4.1. 1 Custom Consumer Interface Test

Define interfaces:

 Copy code-behind code
package Jdk8.Lambda;
import java.util.function.Consumer;
public class LambdaManager {
    public static void userConsumer(String str, Consumer<String> consumer) {
        consumer.accept(str);
    }
}

Interface testing:

 Copy code-behind code
    //Custom Consumer Interface
    @Test
    public void testConsumer() {
//LambdaManager.userConsumer("Hello", new Consumer <String>() {//Implement interfaces using anonymous internal classes
//            @Override
//            public void accept(String s) {
//                System.out.println(s);
//            }
//};// Same as below
        LambdaManager.userConsumer("Hello", (str) -> System.out.println(str));
    }

4.1. Consumer Interface Testing in 2 JDK

Code example: Consumer<T>interface

In JDK1. A default method has been added to the parent Iterable interface of the Collection collection interface in 8:

Public default void for Each (Consumer<? Super T> action) iterates through each element of the Collection collection and performs an "xxx consumer" operation.

In JDK1. A default method has been added to the Map Collection interface in 8:

Public default void for Each (BiConsumer<? Super K,? Super V> action) iterates through each pair of mapping relationships in the Map collection to perform an "xxx consumer" operation.

Case:

(1) Create a collection of Collection series, add programming languages you know, and call the forEach method to iterate through the view

(2) Create a collection of Map series, add some (key,value) key-value pairs, for example, add programming language rankings and language names, call the forEach method to iterate through the view

Sample code:

 Copy code-behind code
    @Test//Consumer interface testing in jdk
    public void testJdkConsumer() {
//Create a List Collection
        List<Integer> list = Arrays.asList(1, 2, 3, 4, 5, 6, 7, 8, 9);
//Traverse through each element of the collection
//        for (Integer integer : list) {
//            System.out.println(integer);
//        }
//        list.forEach(new Consumer<Integer>() {
//            @Override
//            public void accept(Integer integer) {
                integer Is every element traversed,Can print directly
//            }
//}; Jdk already has a foreach defined inside, just call it directly
        list.forEach(i -> System.out.println(i));
        HashMap<Integer, String> map = new HashMap<>();
        map.put(1, "Java");
        map.put(2, "C");
        map.put(3, "C++");
        map.put(4, "JavaScript");
        map.put(5, "c#");
        map.put(6, "Python");
        map.put(7, "PHP");
        map.put(8, "Matlab");
        map.put(9, "Go");
//        map.forEach(new BiConsumer<Integer, String>() {
//            @Override
//            public void accept(Integer integer, String s) {
//System.out.println("number" + integer + "number, value" + s);
//            }
//        });
        map.forEach((i, s) -> System.out.println("No." + i + "individual,Value is" + s));
    }

4.2 Supply Interface

4.2. 1 Custom Supply Interface Test

Define interfaces:

 Copy code-behind code
package Jdk8.Lambda1;
import java.util.function.Supplier;
public class LambdaManager {
    public static void userSupplier(Supplier<String> supplier) {
        String res = supplier.get();
        System.out.println("The value of the call to the supply interface is" + res);
    }
}

Interface testing:

 Copy code-behind code
    //Supply Interface
    @Test
    public void testSupplier() {
//        LambdaManager.userSupplier(new Supplier<String>() {
//            @Override
//            public String get() {
//                return "xiaogao";
//            }
//};// Same as below
        LambdaManager.userSupplier(() -> "xiaogao");
    }

4.2. Supply Interface Test in 2 JDK

Code example: Supplier<T>interface

In JDK1. Stream API, java, was added in 8. Util. Stream. Stream<T>is a data stream. This type has a static method:

Public static <T> Stream <T> generate (Supplier <T> s) creates Stream objects. It also contains a forEach method that traverses elements in the stream: public void for Each (Consumer<? Super T> action).

Case:

Now call Stream's generate method to produce a stream object and call Math. The random() method generates data and assigns values to the parameters of the Supplier functional interface. Finally, the forEach method is called to iterate through the data in the stream to see the results.

 Copy code-behind code
@Test
public void testJdkSupplier(){
    Stream.generate(() -> Math.random()).forEach(num -> System.out.println(num));
}

4.3 Functional Interface

4.3. 1 Custom Functional Interface Test

Define interfaces:

 Copy code-behind code
package Jdk8.Lambda;
import java.util.function.Function;
public class LambdaManager {
   public static void userFunction(String str, Function<String, String> function) {
        String apply = function.apply(str);
        System.out.println("The result returned is" + apply);
    }
}

Interface testing:

 Copy code-behind code
   //Functional interfaces
    @Test
    public void testFunction() {
//        LambdaManager.userFunction("ming", new Function<String, String>() {
//            @Override
//            public String apply(String s) {
//return s += "Hello";
//            }
//        });
        LambdaManager.userFunction("uzi", (s -> s += "How do you do"));
        //Hello uzi, the result returned
    }

4.3. Functional Interface Testing in 2 JDK

Code example: Funtion<T, R>Interface

In JDK1. The Map interface adds many methods at 8:00, such as:

Public default void replaceAll (BiFunction<? Super K,? Super V,? Extends V> function) replaces the value in the map as specified by the function.

Public default void for Each (BiConsumer<? Super K,? Super V> action) iterates through each pair of mapping relationships in the Map collection to perform an "xxx consumer" operation.

 Copy code-behind code
 @Test//Functional interface testing in jdk
    public void testJdkFunction() {
        HashMap<Integer, String> map = new HashMap<>();
        map.put(1, "Java");
        map.put(2, "C");
        map.put(3, "C++");
        map.put(4, "JavaScript");
        map.put(5, "c#");
        map.put(6, "Python");
        map.put(7, "PHP");
        map.put(8, "Matlab");
        map.put(9, "Go");
//Objectives: Replace the name of the java discipline with the name of the java Web
       /* for (Map.Entry<Integer, String> entry : map.entrySet()) {
            Integer key=entry.getKey();
            String value=entry.getValue();
            if (value.equals("Java")) {
                map.put(key,"JavaWeb");
            }
        }//General Writing*/
        /*map.replaceAll(new BiFunction<Integer, String, String>() {
            @Override
            public String apply(Integer k, String v) {
//                Determine if v is java
                if (v.equals("Java")) {
                    return "JavaWeb";
                }
                return v;
            }
        });//Anonymous Internal Class Writing*/
        map.replaceAll((k, v) -> {
            if (v.equals("Java")) {
                return "JavaWeb";
            }
            return v;
        });//Lambda Expression Writing
        map.forEach((i, s) -> System.out.println("No." + i + "individual,Value is" + s));//Print with foreach
    }

4.4 Assertive Interface

4.4. 1 Custom Assertive Interface Test

Define interfaces:

 Copy code-behind code
package Jdk8.Lambda;
import java.util.function.Predicate;
public class LambdaManager {
    public static void userPredicate(String name, Predicate<String> predicate) {
        boolean flag = predicate.test(name);
        System.out.println(flag);
    }
}

Interface testing:

 Copy code-behind code
 //Assertive Interface
    @Test
    public void testPredicate() {
//        LambdaManager.userPredicate("uzi", new Predicate<String>() {
//            @Override
//            public boolean test(String s) {
//                return s.equals("ming");
//            }
//        });
        LambdaManager.userPredicate("ming", (s -> s.equals("ming")));
    }

4.4. 2. jdk interrupt interface testing

Code example: Predicate<T>interface

JDK1. At 8:00, the Collecton <E>interface added one of the following methods:

Public default Boolean removeIf (Predicate<? Super E> filter) is used to delete conditional judgments in a collection that meet the criteria specified by the filter.

Public default void for Each (Consumer<? Super T> action) iterates through each element of the Collection collection and performs an "xxx consumer" operation.

 Copy code-behind code
  @Test
    public void testJdkPredicate() {
    /*
 1)Add some strings to a Collection collection
(2)Call forEach to traverse the collection
(3)Call the removeIf method and delete the
(4)Call forEach again to traverse the collection*/
        ArrayList<String> list = new ArrayList<>();
        list.add("Java");
        list.add("C");
        list.add("Python");
        list.add("PHP");
        list.add("JavaScript");
        //Call forEach to traverse the collection
        list.forEach(s -> System.out.println(s));
        //Call the removeIf method and delete the
        list.removeIf(s -> {
            if (s.length() < 5) {
                return true;
            }
            return false;
        });
        System.out.println("--------------");
        //Call forEach again to traverse the collection
        list.forEach(s -> System.out.println(s));
    }

4.5 Cases

(1) Declare an Employee type including number, name, gender, age, and salary.

(2) Declare an EmployeeSeries employee management class containing all attributes of an ArrayList <Employee>collection, and create some employee objects in the EmployeeSeries constructor to initialize the all collection.

(3) In the EmployeeSeries employee management class, declare a method: ArrayList <Employee> get (Predicate <Employee> p), which adds an employee who meets the conditions specified by P to a new ArrayList <Employee> collection and returns it.

(4) Create an object in the EmployeeSeries employee management class in the test class and call the get method to get:

  • All Employee Objects
  • All employees over 35 years of age
  • All female employees with salaries above 15,000
  • All employees with even numbers
  • Employee with the name "Zhang San"
  • Male Employees Aged Over 25 and Salary Under 10,000

Sample code:

Employee class:

 Copy code-behind code
package com.itheima.pojo;

public class Employee{
        private int id;
        private String name;
        private char gender;
        private int age;
        private double salary;

        public Employee(int id, String name, char gender, int age, double salary) {
                super();
                this.id = id;
                this.name = name;
                this.gender = gender;
                this.age = age;
                this.salary = salary;
        }

        public char getGender() {
                return gender;
        }

        public void setGender(char gender) {
                this.gender = gender;
        }

        public int getAge() {
                return age;
        }

        public void setAge(int age) {
                this.age = age;
        }

        public Employee() {
                super();
        }
        public int getId() {
                return id;
        }
        public void setId(int id) {
                this.id = id;
        }
        public String getName() {
                return name;
        }
        public void setName(String name) {
                this.name = name;
        }
        public double getSalary() {
                return salary;
        }
        public void setSalary(double salary) {
                this.salary = salary;
        }
        @Override
        public String toString() {
                return "Employee [id=" + id + ", name=" + name + ", gender=" + gender + ", age=" + age + ", salary=" + salary
                                + "]";
        }
}

Employee Management:

 Copy code-behind code
class EmployeeService{
        private ArrayList<Employee> all;
        public EmployeeService(){
                all = new ArrayList<Employee>();
                all.add(new Employee(1, "Zhang San", 'male', 33, 8000));
                all.add(new Employee(2, "Jade Blossom", 'female', 23, 18000));
                all.add(new Employee(3, "You're incompetent", 'male', 46, 8000));
                all.add(new Employee(4, "Li Si", 'female', 23, 9000));
                all.add(new Employee(5, "King", 'male', 23, 15000));
                all.add(new Employee(6, "Big mouth", 'male', 23, 11000));
        }
        public ArrayList<Employee> get(Predicate<Employee> p){
                ArrayList<Employee> result = new ArrayList<Employee>();
                for (Employee emp : all) {
                        if(p.test(emp)){
                                result.add(emp);
                        }
                }
                return result;
        }
}

Test class:

 Copy code-behind code
public class TestLambda {
        public static void main(String[] args) {
        //All employees over 35 years of age
                EmployeeManager employeeManager = new EmployeeManager();
        List<Employee> employeeList1 = employeeManager.find(e -> e.getAge() > 35);
        employeeList1.forEach(e -> System.out.println(e));
        //All female employees with salaries above 15,000
        List<Employee> employeeList2 = employeeManager.find(e -> e.getSalary() > 15000 && e.getGender() == 'female');
        employeeList2.forEach(e -> System.out.println(e));
        //All employees with even numbers
        List<Employee> employeeList3 = employeeManager.find(e -> e.getId() % 2 == 0);
        employeeList2.forEach(e -> System.out.println(e));
        //Employee with the name "Zhang San"
        List<Employee> employeeList4 = employeeManager.find(e -> e.getName() == "Zhang San");
        employeeList4.forEach(e -> System.out.println(e));
        //Male Employees Aged Over 25 and Salary Under 10,000
        List<Employee> employeeList5 = employeeManager.find(e -> e.getAge() > 25 && e.getSalary() < 10000 && e.getGender() == 'male');
        employeeList5.forEach(e -> System.out.println(e));
        }
}

5 Method References and Constructor References

Lambda expressions are syntax that simplifies the assignment of variables and parameters to a functional interface. Method and constructor references are used to simplify Lambda expressions. Lambda expressions can also be simplified when they satisfy some special cases:

(1) Lambda body has only one statement and is accomplished by calling an existing method of an object/class

For example: System.out object, calling println() method to complete Lambda body

 Copy code-behind code
      Math Class, call random()Static method complete Lambda body

(2) and the parameter of the Lambda expression is exactly the argument given to the method

For example: t->System. Out. Println(t)

 Copy code-behind code
    () -> Math.random() All without parameters

5.1 Method Reference

Syntax format of method reference:

(1) Instance object name: Instance method

(2) Class name:: Static method

(3) Class name:: Instance method

Explain:

  • :: called method reference operator (two: no spaces in the middle, and must be entered in half-corner in English)
  • The list of parameters for a Lambda expression is used in the Lambda body, either as an object to call a method or as an argument to a method.
  • There is no additional data in the entire Lambda body.
 Copy code-behind code

        @Test
        public void test1(){
//                Runnable r = () -> System.out.println("hello lambda");
                Runnable r = System.out::println;//Print blank lines

                //Method references cannot be simplified because "hello lambda" cannot be omitted
        }

        @Test
        public void test2(){
                String[] arr = {"Hello","java","chai"};
//                Arrays.sort(arr, (s1,s2) -> s1.compareToIgnoreCase(s2));

                //Simplify by Method Reference
                /*
                 * Lambda The first parameter of the expression, for example, s1, happens to be the object calling the method, and the remaining parameter (for example, s2) happens to be the argument given to the method
                 */
                Arrays.sort(arr, String::compareToIgnoreCase);
        }

        @Test
        public void test3(){
//                Stream<Double> stream = Stream.generate(() -> Math.random());

                //Simplify by Method Reference
                Stream<Double> stream = Stream.generate(Math::random);
        }

        @Test
        public void test4(){
                List<Integer> list = Arrays.asList(1,3,4,8,9);

                //list.forEach(t -> System.out.println(t));

                //Method Resimplification
                list.forEach(System.out::println);
        }

5.2 Constructor References

(1) When a Lambda expression creates an object and satisfies the Lambda expression parameters, it is exactly a list of arguments to the constructor that created the object.

(2) When a Lambda expression creates an array object and satisfies the Lambda expression parameter, it is exactly the length of the array object created

The syntax format referenced by the constructor:

  • Class name:new
  • Array type name::new

Sample code:

 Copy code-behind code
public class TestMethodReference {
    @Test
        public void test1() {
                Stream<Integer> stream = Stream.of(1,2,3);
                Stream<int[]> stream2 = stream.map(int[]::new);
        }    

    @Test
        public void test2() {
                Stream<String> stream = Stream.of("1.0","2.3","4.4");

//                Stream<BigDecimal> stream2 = stream.map(num -> new BigDecimal(num));

                Stream<BigDecimal> stream2 = stream.map(BigDecimal::new);
        }

        @Test
        public void test3(){
//Supplier <String> s = () -> new String (); // Provide an empty string object through a Supply-type interface

                //Constructor Reference
                Supplier<String> s = String::new;//Provide an empty string object through a Supply-type interface
        }
}

Scanning VX for Java, Front End, Testing, python, etc.

 

Keywords: Java Back-end

Added by successor on Mon, 13 Dec 2021 20:05:08 +0200