Java learning record (intermediate)-[4], Lambda expression

import java.util.ArrayList;
import java.util.List;
import java.util.Random;

public class LambdaTest {

	public static void main(String[] args) {
		Random r = new Random();
		List<Student> students = new ArrayList<Student>();
		for (int i = 0; i < 5; i++) {
			int age = r.nextInt(6) + 6;
			students.add(new Student("student" + i, age, age % 6 + 1));
		}
		System.out.println("初始化后的集合:");
		System.out.println(students);

		System.out.println("满足条件的学生有:");
		// 这里传递的第二个参数就是Lambda表达式
		// 但实际上,它相当于一个简写的匿名类(实现了StudentChecker接口)
		// s是参数,【->】后是方法体,相当于以下的匿名类
		filter(students, s -> s.age >= 10 && s.grade <= 6);

		/*StudentChecker checker = new StudentChecker() {

			@Override
			public boolean check(Student student) {
				return student.age >= 10 && student.grade <= 6;
			}
		}; // 这和上面的Lambda表达式是一样的效果
		filter(students, checker);*/

	}

	public static void filter(List<Student> list, StudentChecker checker) {
		for (Student student : list) {
			if (checker.check(student)) {
				System.out.println(student);
			}
		}
	}

}

class Student {
	public String name;
	public int age;
	public int grade;

	public Student(String name, int age, int grade) {
		this.name = name;
		this.age = age;
		this.grade = grade;
	}

	@Override
	public String toString() {
		return "\n{Name : " + name + ",Age : " + age + ",Grade : " + grade + "}\n";
	}

}

interface StudentChecker {
	boolean check(Student student);
}

(1) Evolve from anonymous class to Lambda expression

Lambda expressions can be seen as the evolution of anonymous classes a little bit: ↓ ↓ ↓ 
[1], the normal writing of anonymous classes

StudentChecker checker = new StudentChecker() {

	@Override
	public boolean check(Student student) {
		return student.age >= 10 && student.grade <= 6;
	}

};

[2], remove the outer shell, only keep the method parameters and method body, add a symbol between the parameters and the method body [->]

StudentChecker checker = (Student student)->{
		return student.age >= 10 && student.grade <= 6;
};

[3], remove return and {}

StudentChecker checker = (Student student)->student.age >= 10 && student.grade <= 6;

[4]. Remove the parameter type and parentheses (when there is only one parameter, the parentheses can be removed)

StudentChecker checker = student->student.age >= 10 && student.grade <= 6;

[5], pass checker as a parameter

filter(students, checker);

[6], directly pass the expression in

filter(students, s -> s.age >= 10 && s.grade <= 6);

(2) Anonymous method

Compared with the concept of anonymous classes,
Lambda is actually an anonymous method, which is a programming idea that passes methods as parameters .
Although the code is written like this

filter(students, s -> s.age >= 10 && s.grade <= 6);

However, Java will quietly restore these to anonymous classes behind the scenes.
The introduction of Lambda expressions will make the code more compact, instead of various interfaces and anonymous classes flying around.

(3) The disadvantages of Lambda

Although Lambda expressions bring the simplicity of the code, they also have their limitations.
[1]. Poor readability. Compared with the verbose but clear anonymous code structure, once Lambda expressions become longer, it is difficult to understand
[2], it is not easy to debug, and it is difficult to add debugging to Lambda expressions Information such as log
[3] and version support. Lambda expressions are only supported in the JDK8 version. If the system is using the previous version, considering the stability of the system and other reasons, it cannot be used.

Lambda is more suitable for use in short business codes, not suitable for use in complex systems, which will increase maintenance costs.

(4) Method reference

[1], reference static method

[2], reference object method

[3], the method of referencing the object in the container

[4], reference constructor

import java.util.ArrayList;
import java.util.List;
import java.util.Random;

public class LambdaTest {

	public static void main(String[] args) {
		Random r = new Random();
		List<Student> students = new ArrayList<Student>();
		for (int i = 0; i < 5; i++) {
			int age = r.nextInt(6) + 6;
			students.add(new Student("student" + i, age, age % 6 + 1));
		}
		System.out.println("初始化后的集合:");
		System.out.println(students);
		
		// 引用静态方法
		System.out.println("引用静态方法的结果:");
//		filter(students, s->LambdaTest.checkStudent(s));
		filter(students, LambdaTest::checkStudent);
		
		// 引用对象方法
		LambdaTest lambda = new LambdaTest();
		System.out.println("引用对象方法的结果:");
//		filter(students, s->lambda.checkObjectStudent(s));
		filter(students, lambda::checkObjectStudent);
		
		// 引用容器中的对象的方法
		System.out.println("引用容器中的对象的方法的结果:");
//		filter(students, s->s.matched());
		filter(students, Student::matched);
		
		System.out.println("无参的Lambda表达式使用:");
		List list1 = getList(()->new ArrayList<>());
		System.out.println(list1);
		
		System.out.println("引用构造器的结果:");
		List list2 = getList(ArrayList::new);
		System.out.println(list2);

	}

	public static void filter(List<Student> list, StudentChecker checker) {
		for (Student student : list) {
			if (checker.check(student)) {
				System.out.println(student);
			}
		}
	}
	
	public boolean checkObjectStudent(Student student) {
		return student.age >= 10 && student.grade <= 6;
	}
	
	public static boolean checkStudent(Student student) {
		return student.age >= 10 && student.grade <= 6;
	}
	
	public static List getList(Worker<List> w) {
		return w.get();
	}

}

class Student {
	public String name;
	public int age;
	public int grade;

	public Student(String name, int age, int grade) {
		this.name = name;
		this.age = age;
		this.grade = grade;
	}

	@Override
	public String toString() {
		return "\n{Name : " + name + ",Age : " + age + ",Grade : " + grade + "}\n";
	}
	
	public boolean matched() {
		return age >= 10 && grade <= 6;
	}

}

interface StudentChecker {
	boolean check(Student student);
}

interface Worker<T>{
	T get();
}

operation result:

(5), aggregation operation

[1], Tradition data in traditional and aggregate operations

The traditional way to traverse the data is to use a for loop, then conditional judgment, and finally print out the data that meets the condition

for (Hero h : heros) {
   if (h.hp > 100 && h.damage < 50)
      System.out.println(h.name);
}

Using the aggregation operation mode, the style of painting has changed:

heros
	.stream()
	.filter(h -> h.hp > 100 && h.damage < 50)
	.forEach(h -> System.out.println(h.name));

[2], the concept of Stream and pipeline

To understand the aggregation operation, we must first establish the concept of Stream and pipeline.
Stream is different from Collection structured data. Stream is a series of elements, just like cans on the production line.
The pipeline refers to a series of aggregation operations.

【管道】又分3个部分:
管道源:    在这个例子里,源是一个List
中间操作:  每个中间操作,又会返回一个Stream,比如.filter()又返回一个Stream, 中间操作是“懒”操作,并不会真正进行遍历。
结束操作:  当这个操作执行后,流就被使用“光”了,无法再被操作。所以这必定是流的最后一个操作。 结束操作不会返回Stream,但是会返回int、float、String、 Collection或者像forEach,什么都不返回, 结束操作才进行真正的遍历行为,在遍历的时候,才会去进行中间操作的相关判断

[Note: This Stream is a different concept from InputStream and OutputStream in the I/O chapter.

[3], pipeline source

Switching the Collection to the pipeline source is simple, just call stream() .

heros.stream()

But the array has no stream() method , you need to use

Arrays.stream(hs)

or

Stream.of(hs)

[4]. Each intermediate operation of the intermediate operation returns a Stream. For example, .filter() returns a Stream. The intermediate operation is a "lazy" operation and does not really traverse.

中间操作比较多,主要分两类:
1、对元素进行筛选

2、转换为其他形式的流

Common intermediate operations: ↓ ↓ ↓ 

Filter elements Convert to other forms of stream
Operation name Features Operation name Features
filter match mapToDouble Stream converted to double
distinct Remove duplication (according to equals judgment) map Convert to any type of stream
sorted Natural ordering  
sorted(Comparator<T>) Specify sort
limit Keep
skip ignore

[5], end operation

When the end operation is performed, the stream is used "light" and can no longer be operated. So this must be the last operation of the stream. The end operation will not return Stream, but will return int, float, String, Collection, or like forEach, nothing.
The traversal behavior is actually performed after the end operation, and the previous intermediate operation is also executed at this time.

Common end operations: ↓ ↓ ↓ 

Operation name Features
forEach() Loop through each element
min(Comparator<T>) Take the smallest element
max(Comparator<T>) Take the largest element
toArray() Convert to array
count() total
findFirst() The first element

Guess you like

Origin blog.csdn.net/qq_37164975/article/details/82747732