Write interfaces are not just CURD, but they can be more advanced, and we need to look at functional programming before we talk about reactive programming

The concept of functional programming

Use the system’s own functions and Lambda expressions for programming

To take a simple example, find the minimum of an int array

// Define an int array
int[] nums = {1.2.3.4.5};

int min = Integer.MAX_VALUE;
for (int i : nums) {
    if (min > i) {
        min = i;
    }
}
System.out.println(min);
Copy the code

This is the traditional way, the code is very simple, and let’s look at the code for functional programming

System.out.println(IntStream.of(nums).min().getAsInt());
Copy the code

Just a line

First of all, the advantages of functional programming can be reflected from the code, the code is easy to read (first into the flow, and then find the minimum value, and then take out the minimum value)

If the numS array is too large, the efficiency of the single-thread for loop cannot meet the requirements in the traditional way. The first thought is to group the NUMS array and put it into the thread pool for processing. Finally, take out the minimum value of each group and calculate the minimum value again to get the result

Using flow and functional programming, you can change the code to the following:

System.out.println(IntStream.of(nums).parallel().min().getAsInt());
Copy the code

Simply by adding.parallel(), the flow becomes a parallel stream, automatically grouped and multithreaded, and the advantages are obvious

The function interface

Function

= Function
,>

The @functionalInterface annotation is added to the Function

interface. This annotation defines only one method to be implemented in the interface. The default method is not included. It is natural to think that the interface implementation of a method in Lambda expressions would be more concise and consistent with the single responsibility pattern in the design pattern
,>

Function

defines R apply(T T); T represents the input parameter type, R represents the parameter type. This method is what we will use. A simple example is used to demonstrate this
,>

public static void main(String[] args) {
    int num = 123;
    // Call the test method defined below, passing in a function and data to process
    String b = test(a -> String.valueOf(a), num);
    System.out.println(b);
}

// Define a method whose first argument is a function and whose second argument is the data to process
public static String test(Function<Integer, String> func, int a) {
    // Call the apply method of the function, passing in the argument a
    return func.apply(a);
}
Copy the code

String b = test(a -> string.valueof (a), num); String b = test(a -> string.valueof (a)); Such calls are essentially anonymous implementations of the Function interface

Built-in function interface

The JDK includes several other commonly used Function interfaces

interface
The ginseng return
instructions
Predicate<T> T boolean Assertion, often used for filter filtering
Consumer<T> T There is no Only consumption data, no output, is the consumer
Function<T, R> T R Input T, output R
Supplier<T> There is no T No input, output T is the producer
UnaryOperator<T> T T The input and output types are the same
BiFunction<T, U, R> T, U R Input two parameters, output R
BinaryOperator<T> T, T T Input two parameters T, output T, the three data type is the same

These are just interfaces, so you can look at the source code and find the interface definition

A simple example:

// Define an assertion that the input parameter is Integer, the body of the function is less than 0, and returns a Boolean value
Predicate<Integer> a = i -> i < 0;
System.out.println(a.test(123));
Copy the code

Method references

Also to simplify the code, there are the following reference methods

Static method reference

Function<Integer, String> func = a -> String.valueOf(a);
System.out.println(func.apply(123));
Copy the code

In a -> string.valueof (a) above, valueOf is a static method, which can be abbreviated as

Function<Integer, String> func = String::valueOf;
System.out.println(func.apply(123));
Copy the code

A non-static reference

public static void main(String[] args) {
    Test02 test02 = new Test02();
    Function<Integer, String> func = test02::b;
    System.out.println(func.apply(123));
}

public static class Test02 {
    public String b(Integer a) {
        returnString.valueOf(a); }}Copy the code

Constructor reference

public static void main(String[] args) {
    // No arguments
    Supplier<Test02> s1 = Test02::new;
    System.out.println(s1.get());

    // There are parameters
    Function<Long, Test02> s2 = Test02::new;
    // The apply method passes in arguments constructed with arguments
    System.out.println(s2.apply(1L));
}

@Data
public static class Test02 {
    private Long id;

    public Test02(a) {}public Test02(Long id) {
        this.id = id; }}Copy the code

Cascade expressions/higher-order functions

The following functions are called higher-order functions

Function<Integer, Function<Integer, Integer>> func = a -> b -> a + b;

// Call higher-order functions
System.out.println(func.apply(1).apply(2));
Copy the code

A -> b -> a + b

Func.apply (1) returns b -> a + b. Func.apply (1) returns b -> a + b.

When I call.apply(2), B is the input parameter, and the output parameter is a + b, so it actually ends up being 1+2

Why bother writing it?

The goal is to convert a function of multiple arguments into a function of one argument

Code like this:

x -> y -> z = x + y + z;
Copy the code