Java学习记录(中级)——【4】、Lambda表达式

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)、从匿名类演变成Lambda表达式

Lambda表达式可以看成是匿名类一点点演变过来:↓ ↓ ↓ 
[1]、匿名类的正常写法

StudentChecker checker = new StudentChecker() {

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

};

[2]、把外面的壳子去掉,只保留方法参数和方法体,参数和方法体之间加上符号【 ->】

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

[3]、把return和{}去掉

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

[4]、把 参数类型和圆括号去掉(只有一个参数的时候,才可以去掉圆括号)

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

[5]、把checker作为参数传递进去

filter(students, checker);

[6]、直接把表达式传递进去

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

(2)、匿名方法

与匿名类概念相比较,
Lambda 其实就是匿名方法,这是一种把方法作为参数进行传递的编程思想。
虽然代码是这么写

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

但是,Java会在背后,悄悄的,把这些都还原成匿名类方式。
引入Lambda表达式,会使得代码更加紧凑,而不是各种接口和匿名类到处飞。

扫描二维码关注公众号,回复: 12045435 查看本文章

(3)、Lambda的弊端

Lambda表达式虽然带来了代码的简洁,但是也有其局限性。
[1]、可读性差,与啰嗦的但是清晰的匿名类代码结构比较起来,Lambda表达式一旦变得比较长,就难以理解
[2]、不便于调试,很难在Lambda表达式中增加调试信息,比如日志
[3]、版本支持,Lambda表达式在JDK8版本中才开始支持,如果系统使用的是以前的版本,考虑系统的稳定性等原因,而不愿意升级,那么就无法使用。

Lambda比较适合用在简短的业务代码中,并不适合用在复杂的系统中,会加大维护成本。

(4)、方法引用

[1]、引用静态方法

[2]、引用对象方法

[3]、引用容器中的对象的方法

[4]、引用构造器

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();
}

运行结果:

(5)、聚合操作

[1]、传统方式与聚合操作方式遍历数据

遍历数据的传统方式就是使用for循环,然后条件判断,最后打印出满足条件的数据

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

使用聚合操作方式,画风就发生了变化:

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

[2]、Stream和管道的概念

要了解聚合操作,首先要建立Stream和管道的概念
Stream 和Collection结构化的数据不一样,Stream是一系列的元素,就像是生产线上的罐头一样,一串串的出来。
管道指的是一系列的聚合操作。

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

【注: 这个Stream和I/O章节的InputStream,OutputStream是不一样的概念。】

[3]、管道源

把Collection切换成管道源很简单,调用stream()就行了。

heros.stream()

但是数组却没有stream()方法,需要使用

Arrays.stream(hs)

Stream.of(hs)

[4]、中间操作每个中间操作,又会返回一个Stream,比如.filter()又返回一个Stream, 中间操作是“懒”操作,并不会真正进行遍历。

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

2、转换为其他形式的流

常见中间操作:↓ ↓ ↓ 

对元素进行筛选 转换为其他形式的流
操作名 功能 操作名 功能
filter 匹配 mapToDouble 转换为double的流
distinct 去除重复(根据equals判断) map 转换为任意类型的流
sorted 自然排序  
sorted(Comparator<T>) 指定排序
limit 保留
skip 忽略

[5]、结束操作

当进行结束操作后,流就被使用“光”了,无法再被操作。所以这必定是流的最后一个操作。 结束操作不会返回Stream,但是会返回int、float、String、 Collection或者像forEach,什么都不返回,。
结束操作才真正进行遍历行为,前面的中间操作也在这个时候,才真正的执行。

常见结束操作:↓ ↓ ↓ 

操作名 功能
forEach() 遍历每个元素
min(Comparator<T>) 取最小的元素
max(Comparator<T>) 取最大的元素
toArray() 转换为数组
count() 总数
findFirst() 第一个元素

猜你喜欢

转载自blog.csdn.net/qq_37164975/article/details/82747732