summary
Lambda expressions are an important new feature in Java SE 8, based on the mathematical λ-arithmetic of the name, which can also be called closures.
It allows us to passdisplayed formula
Substitute Functional Interface
Similar to methods, Lambda expressions provide a normal list of arguments and a body (body, which can be an expression or a block of code) that uses those arguments
functional interface
To understand Lambda expressions, you first need to understand what a functional interface is, the
It refers toThere is only one abstract method
interface, in addition to the new features of JDK 1.8, the interface can also have thedefault
The default method, which is to have a concrete implementation of the
interface NoParameterNoReturn {
void test();
default void test2() {
System.out.println("JDK1.8 new features, default default method can have a specific implementation");;
}
}
explanatory note
If we declare an interface on@FunctionalInterface annotation
, then the compiler will follow the definition of the functional interface to require that the interface
This way, if there are two abstract methods, then the program compiles with an error
grammatical
Basic syntax: (parameters) -> expression or (parameters) ->{statements; }
Lambda expressions consist of three parts:
- paramaters: similar to the methods in the
formal parameter list (math)
The parameters here are those in the functional interface. Parameter types can be explicitly declared or not declared and implicitly inferred by the JVM. In addition, when there is only one inferred type, the parentheses can be omitted.
- ->: can be interpreted as meaning “to be used for”.
- Method body: can be
displayed formula
It can also becode block
It is an implementation of a method in a functional interface. A block of code can return a value or nothing at all, which in this case is equivalent to the method body of a method. If it is an expression, it can also return a value or nothing at all.
// 1. No parameters, return value is 2.
() -> 2
// 2. Take a parameter (of type numeric) and return two times its value
x -> 2 * x // at this point x can be omitted from the parentheses
// 3. takes 2 arguments (numbers) and returns their sum
(x, y) -> x + y
// 4. Take 2 int integers and return their product.
(int x, int y) -> x * y // can also be written as (x, y), but note that you can't write it as (int x,y), to write it in full
// 5. Receives a String object and prints it without returning any value.
(String s) -> System.out.print(s)
Basic Use of Lambda Expressions
Lambda expressions can be thought of asSimplification of anonymous inner classes
, which actually creates a class that implements the interface and overrides the interface’s methods
For example, we talked about passing comparators to PriorityQueue to build a big heap in an earlier post, and that’s how we wrote it then:
PriorityQueue<Integer> queue = new PriorityQueue<>(new Comparator<Integer>() {
@Override
public int compare(Integer o1, Integer o2) {
return o2.compareTo(o1);
}
});
where new Comparator() and a whole bunch after it are the comparators. The
If Lambda expressions are used, the code can be greatly simplified:
PriorityQueue<Integer> queue = new PriorityQueue<>((o1,o2)->o2.compareTo(o1));
Caveats:
- Parameter types can be omitted, and if they need to be omitted, the type of each parameter should be omitted
- There is only one parameter inside the parentheses of the argument, then the parentheses can be omitted
- If there is only one line of code in the method body, then the curly braces can be omitted.
- If there is only one statement in the method body, and it is a return statement, then you can omit the curly braces and the return keyword
These are pretty easy to remember, that is, when there is only one parameter or only one line of code, you can omit the parentheses and the return
Variable Capture
There is variable capture in Lambda expressions, and by understanding variable capture, we can better understand the scope of Lambda expressions.
Variable capture refers to the process of capturing a variable in theAnonymous Inner Classes or Lambda Expressions
interim reportExternally Scoped Variables
Captured variables require either beingfinal modification
You either have to make sure thatDo not modify it
public interface NoParameterNoReturn {
void test();
}
public static void main(String[] args) {
int size = 10;
//size = 100; can't change the size, otherwise it will report an error.
NoParameterNoReturn noParameterNoReturn = ()-> System.out.println(" This captures the external size: "+size);
noParameterNoReturn.test();
//size = 100; can't change it here either
}
Use of Lambda in Collections
Some new interfaces have been added to collections to interface with Lambda expressions.
connector |
Additional methods |
Collection |
removeIf()、spliterator()、stream()、parallelStream()、forEach() |
List |
replaceAll()、sort() |
Map |
getOrDefault(), forEach(), replaceAll(), putIfAbsent(), remove(), replace(), and so on |
Note: The forEach() method of Collection is taken from the interface java.lang.
Since traversal and sorting are relatively common requirements, we’ll focus on the forEach and sort methods.
🍌forEach()
This method traverses the container
default void forEach(Consumer<? super T> action) {
Objects.requireNonNull(action);
for (T t : this) {
action.accept(t);
}
}
public static void main(String[] args) {
ArrayList<Integer> list = new ArrayList<>();
list.add(2);
list.add(1);
list.add(3);
list.forEach(new Consumer<Integer>() {
@Override
public void accept(Integer integer) {
System.out.print(integer + " ");
}
});
}
The above use of forEach to iterate through the list and print its elements can be simplified with a lambda expression:
list.forEach(x-> System.out.println(x));
You can get the same result
Then we’ll look at the forEach for map, which implements the BiConsumer interface, but otherwise it’s basically the same as the forEach for list, so we’ll just go straight to the lambda expression:
HashMap<String,Integer> map = new HashMap<>();
map.put("a",1);
map.put("b",2);
map.put("c",3);
map.forEach(new BiConsumer<String, Integer>() {
@Override
public void accept(String s, Integer integer) {
System.out.println("key:" + s + " " + "value:"+integer);
}
});
// The result after simplification using lambda expressions.
map.forEach((key,val) -> System.out.println("key:" + key + " " + "value:"+val));
🍌sort
The sort method of list can be used for sorting and needs to be implemented.Comparator interface
list.sort(new Comparator<Integer>() {
@Override
public int compare(Integer o1, Integer o2) {
return o1.compareTo(o2);
}
});
Simplified with lambda it is:
list.sort((o1,o2) -> o1.compareTo(o2));
Here’s an example of sorting
public static void main(String[] args) {
List<String> list = new ArrayList<>();
list.add("sugar");
list.add("hello");
list.add("Lambda");
list.forEach(s-> System.out.print(s + " "));
System.out.println();
list.sort((s1,s2)-> s1.compareTo(s2)); // Sort
list.forEach(s-> System.out.print(s + " "));
}
summarize
The advantages of Lambda expressions are obvious; at the code level, they make the code very concise. However, simplicity comes at a price: it reduces the readability of the code and is not easy to debug.