This series of articles index: "Response spring's DAO spell device"
Previously summary: What is responsive programming | Responsive flow
This article source
1.3 Hello,reactive World
The first two articles introduce the characteristics of responsive programming and responsive streaming, and always talk about the concept of the end is boring, or to tap the code to actually feel the response to the programming of the "feel" bar.
In this section, let's take a look at lambda and functional (already known friends can jump directly to 1.3.2), be familiar with how to use reactor for responsive programming, and then use Spring Boot2, based on Spring 5 Webflux and reactive Spring data progressively develops a "Hello world" level of restful service.
1.3.1 Lambda and functional type
In reactive programming, the rate of lambda and function is quite high, so that friends on the Internet often use "function-responsive programming" in the introduction of "responsive programming". The similarities and differences between the two words have always been controversial, although the difference is not like "JavaScript and Java", "Lei Feng Tower and Leifeng" so big, but casual mixing or will appear very unprofessional:
- The focus of function-responsive programming is on "functional" language features, a concept that was finalized 20 years ago.
- Responsive programming focuses on the asynchronous programming paradigm of "event-based Flow", which drives the execution of logic by constantly generated data/time.
This series of articles deals with "responsive programming", and you'll just have to listen to it and use it with caution when it comes to "function-responsive programming."
1.3.1.1 lambda expression
Why is lambda and function often used in responsive programming, when the book is back? I wonder if you still have an impression of the pseudo-code in section 1.1.3:
cartEventStream // 分别计算商品金额 .map(cartEvent -> cartEvent.getProduct().getPrice() * cartEvent.getQuantity()) ...
cartEventStream
is a data stream in which the element is one cartEvent
, and the map
method is able to cartEvent
"transform/Map", where we convert it to double
the amount of the type.
In addition to the conversion/mapping (map), there are filtering (filter), providing (supply), consumption (consume) and so on the elements of the flow of operations logic/Policy , and logic/policy is usually defined by methods.
Before Java 8, this was a bit of a hassle. We know that Java is an object-oriented programming language, except for a few native types, everything is an object. The method used to define the logical/policy cannot exist independently and must be wrapped in an object. For example, we are more familiar with the Comparator
only way to compare
represent a comparison strategy, when used, it needs to be wrapped in an object to use the method of the policy. Example description (source code):
@Testpublic void Studentcomparetest () {@Data @AllArgsConstructor class Student {//1 private int Id private String name; private double height; private double score; } list<student> students = new arraylist<> (); Students.add (New Student (10001, "Zhang San", 1.73, 88)); Students.add (New Student (10002, "John Doe", 1.71, 96)); Students.add (New Student (10003, "Harry", 1.85, 88)); Class Studentidcomparator<s extends student> implements comparator<s> {//2 @Override public in T compare (s S1, s S2) {return Integer.compare (S1.getid (), S2.getid ()); }} students.sort (new studentidcomparator<> ()); SYSTEM.OUT.PRINTLN (students);}
@Data
And @AllArgsConstructor
is the annotation provided by Lombok, can generate constructs the method, Getter/setter, ToString and so on in the compiled bytecode. Dependencies are as follows:
<dependency> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> <version>1.16.20</version></dependency>
Note: In this section and beyond, you can query the MAVEN search library for new and appropriate versions of MAVEN dependencies.
StudentIdComparator
A comparison strategy is cured in which the object is passed to the Student.id
method when students
it is sorted. StudentIdComparator
sort
The output order is as follows:
[Student (id=10001, Name= Zhang San, height=1.73, score=88.0), Student (id=10002, name= John Doe, height=1.71, score=96.0), Student (id= 10003, Name= Harry, height=1.85, score=88.0)]
Let's say that we need to sort the students ' height or score, the definition Comparator
of the implementation class is a bit cumbersome and unnecessary, and the "traditional" simplification is to pass in the anonymous inner class directly:
students.sort(new Comparator<Student>() { @Override public int compare(Student s1, Student s2) { return Double.compare(s1.getHeight(), s2.getHeight()); } });
But in fact, we will find that no matter what kind of comparison strategy, only compare
the code within the method changes, that is, the sort
method is concerned about only the two parameters passed in Student s1, Student s2
and the return of the conclusion of return Double.compare(s1.getHeight(), s2.getHeight())
this comparison strategy, why not just keep them?
students.sort((Student s1, Student s2) -> {return Double.compare(s1.getHeight(), s2.getHeight());});
This looks like the code is much less. (Student s1, Student s2) -> {return Double.compare(s1.getHeight(), s2.getHeight())}
here is the lambda expression, the syntax for the lambda expression is as follows:
(type1 arg1, type2 arg2...) -> { body }
->
The parameters and method bodies are represented before and after each. From the way code is written, this can be counted as a "functional" programming paradigm, as we pass to sort
a "function" in the form of a lambda expression, which has inputs and outputs that the developer appears to be naked and not encapsulated with objects.
One of the core features of the "functional" programming Paradigm: A function is a "class citizen".
The so-called "first Class" refers to functions that are equal to other data types, can be assigned to other variables, can also be passed as arguments to another function, or as a return value for other functions.
But it is only "looks" is "functional", Java is ultimately object-oriented language, List.sort
the method definition is still to accept an Comparator
object as a parameter. But do you have to tangle with Java as a purely functional language? There is no need, practical first.
So, the question is, sort
how do you think of this lambda "as" an Comparator
object?
It is not difficult to see that Comparator
an interface has only one abstract method, so it is sort
not difficult to "infer" that the input parameters and method bodies defined by Lambda are exactly the only abstract method compare
.
1.3.1.2-Functional Interface
Comparator
an interface like this, which has only one abstract method, is called a functional interface (functional Interface). As with Comparator
similar, the only abstract method of other functional interfaces can also be represented by Lambda.
We look at Comparator
the source code, found that it is a more @FunctionalInterface
annotated, to indicate that it is a functional interface. The interface marked with this annotation has only one abstract method, otherwise it will report a compilation error.
Look at the other interfaces that have only one abstract method, such as Runnable
and Callable
, the discovery also adds annotations after Java 8 @FunctionalInterface
. For runnable, the interface is defined as follows:
@FunctionalInterfacepublic interface Runnable { public abstract void run();}
It is not difficult to speculate that its lambda should be () -> { body }
written, it does not receive any parameters, the method body also has no return
return value, used like this:
new Thread(() -> {doSomething();});
In addition, with the addition of lambda, there is a java.util.function
package that defines some of the common function-type interfaces. Like what:
Function
, takes an input parameter and returns a result. The type of the parameter and the return value can be different, the map
lambda in our previous method is the expression of this function interface;
Consumer
, accepts an input parameter and has no returned action. For example, if we print every element of the data stream, we can use Consumer
lambda based;
Supplier
, no input parameters are required and only the results are returned. Look at the interface name to know is to play the role of the object factory;
Predicate
, takes an input parameter and returns a Boolean result. For example, when we filter the elements in the data flow, we can use lambda based Predicate
;
- ...
1.3.1.3 Simplified Lambda
The method of using lambda as a parameter can infer the abstract method of which function interface the lambda represents. Similarly, the compilation period can be more inferred. Let's go back to the original Comparator
example and continue simplifying the lambda expression as follows:
students.sort((Student s1, Student s2) -> {return Double.compare(s1.getHeight(), s2.getHeight());});
1) First, the type of the parameter passed in can be inferred. Because it students
is an Student
array of elements List<Student>
, its sort
methods naturally receive Comparator<? super Student>
objects as parameters, all of which can be constrained by generics.
students.sort((s1, s2) -> {return Double.compare(s1.getHeight(), s2.getHeight());});
2) If there is only one return
statement, return
and the curly braces of the method body can be omitted ( compare
the return value of the method is the lambda return value):
students.sort((s1, s2) -> Double.compare(s1.getHeight(), s2.getHeight()));
3) Note that the Comparator
interface also provides a rich static method, such as:
public static<T> Comparator<T> comparingDouble(ToDoubleFunction<? super T> keyExtractor) { Objects.requireNonNull(keyExtractor); return (Comparator<T> & Serializable) (c1, c2) -> Double.compare(keyExtractor.applyAsDouble(c1), keyExtractor.applyAsDouble(c2));}
This method has been packaged for us Double.compare
. It receives a functional interface with a return type, which Double
ToDoubleFunction<? super T>
can be seen as a Function<? super T, Double>
lambda representation student -> student.getHeight()
.
Therefore, our sort
approach can also be written:
students.sort(Comparator.comparingDouble((student) -> student.getHeight()));
First, for a lambda with only one parameter, the parentheses outside the argument can be omitted:
students.sort(Comparator.comparingDouble(student -> student.getHeight()));
Second, for a lambda method body with only one method invocation, which can be further 类::方法
simplified, the above code can be further simplified to:
students.sort(Comparator.comparingDouble(Student::getScore));
Here is a method that invokes the object represented by the argument, similar to the following example:
string -> System.out.println(string)
, can be simplified as System.out::println
, here is the parameter as System.out::println
the parameter;
() -> new HashMap<>()
, can be simplified as, there are HashMap::new
no parameters, can also be simplified.
The use 类::方法
of this style is not more functional sense, it seems that the function as a parameter to a method of it?
No further examples of these simplified form xxx you may feel difficult to remember, in fact, no memory, most Ides can provide simplified recommendations.
1.3.1.4 Summary
In the world of programming languages, Java is like a moderate middle-aged man, it always puts backward compatibility and stability in the first place, not casually because of some language features or grammatical sugar, but for the language features with significant expected benefits will be decisive attack, generics so, Lambda also is so, Perhaps the introduction of them is not thorough and perfect, but it is practical enough to bring great convenience to the developers. This should also be one of the reasons why the Java language can continue to stay alive!
As for the more complex concepts of functional aspects, there is not much to be described here. Now let's meet reactor.
(3) Lambda and function--response spring's DAO spell device