Java Lambda expressions are a new feature introduced by Java 8. They can be said to be a syntax sugar for simulated functional programming. They are similar to closures in Javascript, but they are somewhat different. The main purpose is to provide a functional syntax to simplify our encoding.
Lambda basic syntax
The basic structure of Lambda is (arguments) -> body, and there are several situations:
Body needs to include statements with {}, and {} can be omitted when there is only one statement.
Common writing methods are as follows:
(a) -> a * a
(int a, int b) -> a + b
(a, b) -> {return a - b;}
() -> System.out.println(Thread.currentThread().getId())
FunctionalInterface
concept
Java Lambda expressions are based on functional interfaces. What is a functional interface? Simply put, it is an interface with only one method (function). The purpose of this type of interface is for a single operation, which is equivalent to a single function. Common interfaces such as Runnable and Comparator are functional interfaces, and are annotated with @FunctionalInterface.
Give an example
It is easy to understand using Thread as an example. The Runnable interface is an interface commonly used when we thread programming, which includes a method void run(), which is the thread's running logic. According to the previous syntax, we usually use Runnable anonymous class to create new threads, as follows:
new Thread(new Runnable() { @Override public void run() { System.out.println(Thread.currentThread().getId()); }}).start();If you write too much, isn't it boring? The writing rules based on Lambda become concise and clear, as follows:
new Thread(() -> System.out.println(Thread.currentThread().getId())).start();
Pay attention to the parameters of Thread. The anonymous implementation of Runnable is implemented in one sentence, and it is written as the following one to better understand.
Runnable r = () -> System.out.println(Thread.currentThread().getId());
new Thread(r).start();
Of course, Lambda's purpose is not just to write concisely, but to summarize the higher-level purpose after understanding it.
Let’s look at another example of a comparator. According to the traditional writing method, 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; }});Lambda expressions are written as follows:
Integer[] a = {1, 8, 3, 9, 2, 0, 5};
Arrays.sort(a, (o1, o2) -> o1 - o2);
Functional interfaces in JDK
In order for the existing class library to directly use Lambda expressions, there were some interfaces in Java 8 that had been marked as functional interfaces:
A new package java.util.function has been added to Java 8, bringing the commonly used functional interface:
In addition, more specific functions are added to the processing of basic types, including: BooleanSupplier, DoubleBinaryOperator, DoubleConsumer, DoubleFunction<R>, DoublePredicate, DoubleSupplier, DoubleToIntFunction, DoubleToLongFunction, 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>. Combined with the above functional interfaces, you can see the role of the interface at a glance through the class name of these basic functional interfaces.
Create a functional interface
Sometimes we need to implement a functional interface ourselves, and the method is very simple. First, you must ensure that this interface can only have one function operation, and then annotate @FunctionalInterface on the interface type.
Type Derivation
Type derivation is the basis of Lambda expressions, and the process of type derivation is the compilation process of Lambda expressions. The following code is an example:
Function<String, Integer> strToInt = str -> Integer.parseInt(str);
During compilation, the process of type derivation I understand is as follows:
The target type here is the key, and the method signature is obtained through the target type and then compare it with the Lambda expression.
Method reference
The basis of method reference (Method Reference) is also a functional interface, which can be directly implemented as a functional interface, has the same function as Lambda expressions and also depends on type derivation. Method references can be seen as simplification of Lambda expressions that call only one method.
The syntax referenced by the method is: Type::methodName or instanceName::methodName, and the methodName corresponding to the constructor is new.
For example, the examples were used above:
Function<String, Integer> strToInt = str -> Integer.parseInt(str);
The corresponding method reference is
Function<String, Integer> strToInt = Integer::parseInt;
According to the type of method, method references are mainly divided into the following types: constructor method reference, static method reference, instance method reference on instance, instance method reference on type, etc.
Constructor method reference
The syntax is: Type::new. For example, the following function is to convert a string into an array
Method reference writing
Function<String, Integer> strToInt = Integer::new;
Lambda writing
Function<String, Integer> strToInt = str -> new Integer(str);
Traditional writing
Function<String, Integer> strToInt = new Function<String, Integer>() { @Override public Integer apply(String str) { return new Integer(str); }};
Array constructor reference
The syntax is: Type[]::new . For example, the following function is to construct a string array of specified length
Method reference writing
Function<Integer, String[]> fixedArray = String[]::new;
Method reference writing
Function<Integer, String[]> fixedArray = length -> new String[length];
Traditional writing
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 the following function is also used to convert strings into arrays
Method reference writing
Function<String, Integer> strToInt = Integer::parseInt;
Lambda writing
Function<String, Integer> strToInt = str -> Integer.parseInt(str);
Traditional writing
Function<String, Integer> strToInt = new Function<String, Integer>() { @Override public Integer apply(String str) { return Integer.parseInt(str); }};Instance method reference on an instance
The syntax is: instanceName::methodName. For example, the following judgment function is used to determine whether the given name exists in the list
List<String> names = Arrays.asList(new String[]{"Zhang San", "Li Si", "Wang Wu"});
Predicate<String> checkNameExists = names::contains;
System.out.println(checkNameExists.test("Zhang San"));
System.out.println(checkNameExists.test("Zhang Si"));
Instance method reference on type
The syntax is: Type::methodName . Runtime reference refers to an object in the context, such as the function below to return the length of the string
Function<String, Integer> calcStrLength = String::length;System.out.println(calcStrLength.apply("Zhang San"));List<String> names = Arrays.asList(new String[]{"zhangsan", "lisi", "wangwu"});names.stream().map(String::length).forEach(System.out::println);
For example, the following function has specified a separator to split the string into an array
BiFunction<String, String, String[]> split = String::split;
String[] names = split.apply("zhangsan,lisi,wangwu", ",");
System.out.println(Arrays.toString(names));
Stream Objects
concept
What is Stream? The Stream here is different from InputStream and OutputStream in io. Stream is located in the package java.util.stream and is also newly added to Java 8. Stream is only a set of elements that support serial parallel aggregation operations, which can be understood as an enhanced version of a collection or iterator. What is an aggregation operation? To give a simple example, common ones include mean, maximum, minimum, sum, sort, filtering, etc.
Several features of Stream:
Single processing. After one processing is completed, the current Stream is closed.
Support common ways to get Streams in parallel operations
Get from the collection
Collection.stream();
Collection.parallelStream();
Static factory
Arrays.stream(array)
Stream.of(T…)
IntStream.range()
Here we will only give a brief introduction to Stream, and there will be specific applications below. If you want to talk about the relationship between Stream and Lambda expressions, there is actually no particularly close relationship. It’s just that Lambda expressions greatly facilitate the use of Stream. Without Lambda expressions, a large number of anonymous classes will be generated during the use of Stream, which is very awkward.
Give an example
The following demos depend on the Employee object and the List object composed 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("Zhang San", "Male", 25)); employees.add(new Employee("Li Si", "Female", 24)); employees.add(new Employee("Wang Wu", "Female", 23));employees.add(new Employee("Saturday", "Male", 22));employees.add(new Employee("Sun Qi", "Female", 21));employees.add(new Employee("Liu Ba", "Male", 20));Print all employees
Collection provides the forEach method for us to operate individual objects one by one.
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/min element under specified sorting conditions
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 years old
filters out elements that meet the criteria
Employees.stream()
.filter(e -> e.getAge() > 20 && "male".equals(e.getSex()))
.forEach(e -> System.out.println(e));
Print out the two oldest male employees
The limit method intercepts limited elements
employees.stream() .filter(e -> "Male".equals(e.getSex())) .sorted((e1, e2) -> e2.getAge() - e1.getAge()) .limit(2) .forEach(e -> System.out.println(e));
Print out the names of all male employees, use, separate
map to form a new Stream after executing the given function.
String maleEmployeesNames = employees.stream() .map(e -> e.getName()) .collect(Collectors.joining(","));System.out.println(maleEmployeesNames);Statistical information
IntSummaryStatistics, DoubleSummaryStatistics, LongSummaryStatistics Contains the summary data in the Stream.
IntSummaryStatistics stat = employees.stream() .mapToInt(Employee::getAge).summaryStatistics();System.out.println("Total number of employees:" + stat.getCount());System.out.println("Maximum age:" + stat.getMax());System.out.println("Minimum age:" + stat.getMin());System.out.println("Average age:" + stat.getAverage());Summarize
Lambda expressions can indeed reduce a lot of code and improve productivity. Of course, there are disadvantages, that is, complex expressions will be poorly readable, or it may be because they are not very used to it. If you get used to it, I believe you will like it. Everything has two sides, it depends on how we balance the pros and cons, especially in a team.
The above is the information sorting out Java8 JavaLambda. We will continue to add relevant information in the future. Thank you for your support for this website!