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表达式,会使得代码更加紧凑,而不是各种接口和匿名类到处飞。

(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()第一个元素
(1)普通用户端(全平台) 音乐播放核心体验: 个性化首页:基于 “听歌历史 + 收藏偏好” 展示 “推荐歌单(每日 30 首)、新歌速递、相似曲风推荐”,支持按 “场景(通勤 / 学习 / 运动)” 切换推荐维度。 播放页功能:支持 “无损音质切换、倍速播放(0.5x-2.0x)、定时关闭、歌词逐句滚动”,提供 “沉浸式全屏模式”(隐藏冗余控件,突出歌词与专辑封面)。 多端同步:自动同步 “播放进度、收藏列表、歌单” 至所有登录设备(如手机暂停后,电脑端打开可继续播放)。 音乐发现与管理: 智能搜索:支持 “歌曲名 / 歌手 / 歌词片段” 搜索,提供 “模糊匹配(如输入‘晴天’联想‘周杰伦 - 晴天’)、热门搜索词推荐”,结果按 “热度 / 匹配度” 排序。 歌单管理:创建 “公开 / 私有 / 加密” 歌单,支持 “批量添加歌曲、拖拽排序、一键分享到社交平台”,系统自动生成 “歌单封面(基于歌曲风格配色)”。 音乐分类浏览:按 “曲风(流行 / 摇滚 / 古典)、语言(国语 / 英语 / 日语)、年代(80 后经典 / 2023 新歌)” 分层浏览,每个分类页展示 “TOP50 榜单”。 社交互动功能: 动态广场:查看 “关注的用户 / 音乐人发布的动态(如‘分享新歌感受’)、好友正在听的歌曲”,支持 “点赞 / 评论 / 转发”,可直接点击动态中的歌曲播放。 听歌排行:个人页展示 “本周听歌 TOP10、累计听歌时长”,平台定期生成 “全球 / 好友榜”(如 “好友中你本周听歌时长排名第 3”)。 音乐圈:加入 “特定曲风圈子(如‘古典音乐爱好者’)”,参与 “话题讨论(如‘你心中最经典的钢琴曲’)、线上歌单共创”。 (2)音乐人端(创作者中心) 作品管理: 音乐上传:支持 “无损音频(FLAC/WAV)+ 歌词文件(LRC)+ 专辑封面” 上传,填写 “歌曲信息
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

十甫寸木南

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值