Java LAMBDA expressions are a new feature introduced in Java 8, a syntactic candy that simulates functional programming, similar to a closure in Javascript, but somewhat different, primarily to provide a functional syntax to simplify our coding.
LAMBDA Basic Syntax
The basic structure of the LAMBDA is (arguments)-> body, there are several situations:
- When a parameter type is inferred, no type needs to be specified, such as (a)-> System.out.println (a)
- When there is only one argument and the type can be inferred, do not force write (), such as a-> System.out.println (a)
- Parameter must have parentheses when specifying a type, such as (int a)-> System.out.println (a)
- Parameter can be empty, such as ()-> System.out.println ("Hello")
The body needs to contain the statement with {}, when only one statement {} can be omitted
The common wording is as follows:
(a)-> a * a
(int a, int b)-> A + b
(A, B)-> {return a-b;}
()-> System.out.println (Thread.CurrentThread (). GetId ())
Function-type interface Functionalinterface
Concept
Java Lambda expressions are based on functional interfaces. What is a functional interface (Functionalinterface)? In short, there is only one method (function) interface, which is intended for a single operation and is equivalent to a single function. Common interfaces such as: Runnable, Comparator are functional interfaces, and all annotations are annotated @FunctionalInterface.
Example
Taking Thread as an example shows that it's easy to understand. The Runnable interface is a common interface for threading programming, and contains a method void run (), which is the logic of the thread's operation. In the previous syntax, our new thread typically uses the Runnable anonymous class, as follows:
New Thread (New Runnable () {
@Override public
void Run () {
System.out.println thread.currentthread (). GetId ());
Start ();
If it's too much to write, it's boring, and the Lambda-based writing becomes simple and straightforward, as follows:
New Thread (()-> System.out.println (Thread.CurrentThread (). GetId ())). Start ();
Note the parameters of the Thread, Runnable Anonymous implementation is achieved by a sentence, written below to better understand
Runnable r = ()-> System.out.println (Thread.CurrentThread (). GetId ());
New Thread (R). Start ();
Of course, the purpose of LAMBDA is not only to write concise, a higher level of purpose and so on to conclude.
Look at an example of a comparator, according to the traditional wording, as follows:
Integer[] A = {1, 8, 3, 9, 2, 0, 5};
Arrays.sort (A, new comparator<integer> () {
@Override public
int compare (integer o1, integer o2) {
return o1-o2;
}
});
The LAMBDA expression is written as follows:
Integer[] A = {1, 8, 3, 9, 2, 0, 5};
Arrays.sort (A, (O1, O2)-> O1-o2);
Functional interfaces in the JDK
For existing class libraries to be able to use LAMBDA expressions directly, some of the previous interfaces of Java 8 have been labeled as functional interfaces:
- Java.lang.Runnable
- Java.util.Comparator
- Java.util.concurrent.Callable
- Java.io.FileFilter
- Java.security.PrivilegedAction
- Java.beans.PropertyChangeListener
Java 8 is a new addition to the package java.util.function, bringing the common functional interface:
- function<t, r>-function: input t output r
- bifunction<t, U, r>-function: input t and U output R object
- Predi Cate<t>-assertion/judgment: input T output boolean
- bipredicate<t, u>-assertion/judgment: input T and U output Boolean
- SUPPLIER&L T T>-Producer: no input, output T
- consumer<t>-Consumer: input T, no output
- biconsumer<t, u>-Consumer: input T and U no output
- unaryoperator<t>-cell operation: input t output t
- binaryoperator<t>-Two-dollar operation: input T and t output T
In addition, more specific functions are added to the basic type of processing, including: Booleansupplier, Doublebinaryoperator, Doubleconsumer, Doublefunction<r> Doublepredicate, Doublesupplier, Doubletointfunction, Doubletolongfunction, Doubleunaryoperator, IntBinaryOperator, Intconsumer, Intfunction<r>, Intpredicate, Intsupplier, Inttodoublefunction, Inttolongfunction, Intunaryoperator, Longbinaryoperator, Longconsumer,longfunction<r>, Longpredicate, LongSupplier, Longtodoublefunction,longtointfunction, Longunaryoperator, Todoublebifunction<t, U>, ToDoubleFunction<T >,tointbifunction<t, U>, Tointfunction<t>, Tolongbifunction<t, U>, ToLongFunction<T>. With the above functional interface, the function interface of these basic types can see the function of the interface through the class name.
To create a functional interface
Sometimes we need to implement a functional interface, the practice is very simple, first of all you have to ensure that this interface can only have a function operation, and then on the interface type annotation @FunctionalInterface can be.
Type inference
Type inference is the basis of lambda expressions, and the process of type derivation is the compilation of lambda expressions. Take the following code as an example:
function<string, integer> strtoint = str-> integer.parseint (str);
During compilation, I understand the process of type derivation as follows:
- Determine the target type Function first
- function as a functional interface whose method signature is: Integer apply (String t)
- Detect if str-> integer.parseint (str) matches the method signature (parameter type, number, order, and return value type of the method)
- If it does not match, a compile error is reported
The target type here is the key, gets the method signature through the target type, and then contrasts with the LAMBDA expression.
Method reference
The basis of a method reference (methods Reference) is also a functional interface, which can be implemented directly as a function interface, and has the same effect as a LAMBDA expression, and also relies on type inference. A method reference can be considered a simplification of a LAMBDA expression that invokes only one method.
The syntax for the method reference is: Type::methodname or Instancename::methodname, and the constructor corresponds to the MethodName for new.
For example, the above examples were used:
function<string, integer> strtoint = str-> integer.parseint (str);
The corresponding method reference is written as
function<string, integer> strtoint = Integer::p arseint;
Depending on the type of method, the method reference is mainly divided into several types, such as constructor reference, static method reference, instance method reference on instance, instance method reference on type, etc.
To construct a method reference
The syntax is: type::new. Like the following function to convert a string to an array
Method reference notation
function<string, integer> strtoint = integer::new;
Lambda notation
function<string, integer> strtoint = str-> new Integer (str);
Traditional wording
function<string, integer> strtoint = new function<string, integer> () {
@Override public
Integer Apply (String str) {return
new Integer (str);
}
;
Array constructor Method reference
The syntax is: type[]::new. As in the following function to construct a string array of a specified length
Method reference notation
Function<integer, string[]> fixedarray = string[]::new;
Method reference notation
Function<integer, string[]> fixedarray = length-> new string[length];
Traditional wording
Function<integer, string[]> fixedarray = new Function<integer, string[]> () {
@Override
public String[] Apply (Integer length) {return
new string[length];
}
;
static method Reference
The syntax is: type::new. As in the following function to convert a string to an array
Method reference notation
function<string, integer> strtoint = Integer::p arseint;
Lambda notation
function<string, integer> strtoint = str-> integer.parseint (str);
Traditional wording
function<string, integer> strtoint = new function<string, integer> () {
@Override public
Integer Apply (String str) {return
integer.parseint (str);
}
;
instance method reference on instance
The syntax is: Instancename::methodname. The following judgment function is used to determine whether a given name exists in the list
list<string> names = arrays.aslist (new string[]{"John", "Dick", "Harry"});
predicate<string> checknameexists = names::contains;
System.out.println (Checknameexists.test ("John"));
System.out.println (checknameexists.test ("Zhang Si"));
instance method reference on type
The syntax is: Type::methodname. A run-time reference is an object in the context, such as the following function to return the length of a string
function<string, integer> calcstrlength = string::length;
System.out.println (Calcstrlength.apply ("John"));
list<string> names = arrays.aslist (new string[]{"Zhangsan", "Lisi", "Wangwu"});
Names.stream (). Map (String::length). ForEach (System.out::p rintln);
For example, the following function has specified a delimiter split string as an array
Bifunction<string, String, string[]> split = String::split;
string[] names = split.apply ("Zhangsan,lisi,wangwu", ",");
System.out.println (arrays.tostring (names));
Stream Object
Concept
What is Stream? The stream here differs from the IO InputStream and Outputstream,stream in the package Java.util.stream, which is also a new Java 8 addition, stream is a set of elements that support serial parallel aggregation operations, and can Understood as an enhanced version of a collection or iterator. What is an aggregation operation? Simple examples of common averages, maximum, minimum, sum, sorting, filtering, and so on.
Several characteristics of the Stream:
Single processing. At the end of the process, the current stream is closed.
Support for parallel operations
Common way to get the Stream
Gets from the collection
Collection.stream ();
Collection.parallelstream ();
Static Factory
Arrays.stream (Array)
Stream.of (T ...)
Intstream.range ()
Here is a simple introduction to the Stream, the following will have specific applications. There is nothing particularly close to the relationship between the stream and the lambda expression, but the lambda expression greatly facilitates the use of the stream. If there is no LAMBDA expression, the use of the Stream will produce a large number of anonymous classes, very awkward.
Example
The following demo relies on the employee object and the List object made up of the employee object.
public class Employee {private String name;
Private String sex;
private int age;
Public Employee (string name, string sex, int age) {super ();
THIS.name = name;
This.sex = sex;
This.age = age;
Public String GetName () {return name;
Public String Getsex () {return sex;
public int getage () {return age;
@Override public String toString () {StringBuilder builder = new StringBuilder (); Builder.append ("Employee {name="). Append (name). Append (", sex="). Append (Sex). Append (", age="). Append (age). Append ("
}");
return builder.tostring ();
} list<employee> Employees = new arraylist<> ();
Employees.add (New Employee ("John", "Male", 25));
Employees.add (New Employee ("Dick", "female", 24));
Employees.add (New Employee ("Harry", "female", 23));
Employees.add (New Employee ("Saturday", "male", 22));
Employees.add (New Employee ("Sun Seven", "female", 21));
Employees.add (New Employee ("Liu Eight", "male", 20));
Print all employees
Collection provides a ForEach method for us to manipulate individual objects individually.
Employees.foreach (e-> System.out.println (e));
Or
Employees.stream (). ForEach (e-> System.out.println (e));
Sort by age
Collections.sort (Employees, (E1, E2)-> e1.getage ()-e2.getage ());
Employees.foreach (e-> System.out.println (e));
Or
Employees.stream (). Sorted (E1, E2)-> e1.getage ()-e2.getage ()). ForEach (e-> System.out.println (e));
Print the oldest female employee
Max/min returns the largest/smallest element under the specified sort condition
Employee Maxagefemaleemployee = Employees.stream ()
. Filter (E-> "female". Equals (E.getsex ())
. Max (E1, E2)- > E1.getage ()-e2.getage ())
. get ();
System.out.println (Maxagefemaleemployee);
Print out male employees older than 20
Filter filters out elements that meet the criteria
Employees.stream ()
. Filter (e-> e.getage () > && "Male". Equals (E.getsex ()))
. ForEach (e-> System.out.println (e));
Print out the oldest 2 male employees
Limit method intercepts a finite element
Employees.stream ()
. Filter (E-> "man". Equals (E.getsex ()))
. Sorted (e1, E2)-> e2.getage ()-e1.getage ())
. Limit (2)
. ForEach (E-> System.out.println (e));
Print out the names, use, and separation of all male employees
Map composes the new stream with the returned value of the function given by the execution of all elements in the stream
String maleemployeesnames = Employees.stream ()
. Map (e-> e.getname ())
. Collect (Collectors.joining (","));
System.out.println (Maleemployeesnames);
Statistical information
Intsummarystatistics, Doublesummarystatistics, Longsummarystatistics contains the summarized data in the Stream.
Intsummarystatistics stat = Employees.stream ()
. Maptoint (Employee::getage). Summarystatistics ();
SYSTEM.OUT.PRINTLN ("Total staff:" + stat.getcount ());
System.out.println ("The highest Age:" + Stat.getmax ());
System.out.println ("Minimum Age:" + stat.getmin ());
System.out.println ("average age:" + stat.getaverage ());
Summarize
Lambda expressions can really reduce a lot of code, can improve productivity, and of course, there are drawbacks, is the complexity of the expression is less readable, it may be not very accustomed to the sake of it, if accustomed to, I believe will like. Everything has two sides, it depends on how we balance the pros and cons, especially in a team.
The above is the JAVA8 JAVALAMBDA data collation, follow-up continue to supplement the relevant information thank you for your support of this site!