前序 Lambda 表达式 介绍:
1:在 java 8 中引入了一个新的操作符"->",该操作符称为箭头操作符或Lambda操作符。2:箭头操作符将Lambda表达式才分为两部分。
左侧:Lambda 表达式的参数列表。
右侧:Lambda 体,即对接口的实现。
3:学习 Lambda 表达式先 应该了解一个知识点 ”函数式接口“,使用 Lambda 表达式必须要有“函数式接口”支持。
@FunctionalInterface 注解:
该注解能够强制要求接口为 ”函数式接口“
代码演示:不用 @FunctionalInterface 注解:
packagecom.test.factory;public interfaceFunctionalInterfaceTest {/*** 获取 用户姓名
*@return
*/String getName();/*** 获取用户年龄*/
voidgetage();
}
代码演示:使用@FunctionalInterface 注解: 存在了多个 抽象方法,所以指定 该注解 会报错,意思就是该接口必须指定成 “函数式接口”。
若接口中存在 一个以上的抽象方法,就不能称之为 ”函数式接口", @FunctionalInterface 可以强制要求该类必须为“函数式接口”。
若要定义 “函数式接口” 只需要保存一个 抽象方法 即可。用不用 @FunctionalInterface 注解都不重要
如下图:只保留一个 抽象方法,就是一个合法的 “函数式接口”。
经典的函数式接口:Runnable
学习过多线程的朋友应该很清楚这个 接口。
“函数式接口" 定义总结:
“函数式接口” 的含义:
核心:就是为了支持 Lambda 表达式 所定义的接口,
定义:“函数式接口” 必须保证 该接口 只有一个 抽象方法。
@FunctionalInterface注解:可以强制要求 该接口必须为 “函数式接口”。
Lambda 表达式 优点:
Lambda 表达式 只有一个优点:省,简化重复代码,只保留核心代码。使代码逻辑更加清晰。
Lambda 表达式 代码演示:
多说无益,看不到效果,即便说的天花烂醉又是如何?接下来统过一个 小小的案例,见识一下 Lambda 表达式 的 魅力之处。
需求:有一组员工信息存放到一个集合中,并且按照不同需求,来获取员工信息。
声明:案例展示中的案例 来源于 https://www.bilibili.com/video/av71563078?p=2 ,代码是我学习时按照视频课程内容讲解敲的(主要是想思考Lambda 的 演进过程,实际工作中用过Lambda,只是不知道是Lambda表达式,当时很傻的以为是idea 支持这么做)。
记录博客,只是单纯的记录一下学习笔记,看别人的代码还不如自己动手敲一遍,找个差不多的案例。如有侵权,请联系我,我会主动删除。
对于内容思考有所不对的地方请指明出来,一起学习,一起进步。
再次声明:以下代码只是我学习时,练手代码,对于质量我不敢保证,真正想学习 Lambda 的朋友,可以看视频教程或其他高质量的博客。
案例展示:
员工实体对象
/***@authorAdministrator
*@version1.0
* @describe 员工信息 POJO
* @date 2019/12/20 19:52*/
public classStaffModel {/*** 姓名*/
privateString name;/*** 年龄*/
private intage;/*** 性别*/
private chargender;/*** 薪资*/
private doublesalary;
get()...
set()...
toString()...
}
员工信息集:以下案例会都用这些数据。
public classLambdaTest {private static List staffModelList=new ArrayList<>();static{
staffModelList.add(new StaffModel("张三",25,'男',5000));
staffModelList.add(new StaffModel("村花",25,'女',5500));
staffModelList.add(new StaffModel("李飞飞",21,'男',2000));
staffModelList.add(new StaffModel("牛妞妞",30,'女',10000));
staffModelList.add(new StaffModel("王晓非",24,'男',6000));
}
}
传统方式:
案例一:普通的获取 工作大于或等于5000的 员工信息
/*** 需求一:获取员工中 工资大于或五千的 员工信息
*@return
*/
public static List salaryFilter(Listlist){
List staffModelList=new ArrayList<>();for (int i = 0; i < list.size(); i++) {if (list.get(i).getSalary() >= 5000) {
staffModelList.add(list.get(i));
}
}returnstaffModelList;
}/*** 测试
*@paramargs*/
public static voidmain(String[] args) {
System.out.println(salaryFilter(staffModelArrayList));
}//结果
[StaffModel{name='张三', age=25, gender=男, salary=5000.0},
StaffModel{name='村花', age=25, gender=女, salary=5500.0},
StaffModel{name='牛妞妞', age=30, gender=女, salary=10000.0},
StaffModel{name='王晓非', age=24, gender=男, salary=6000.0}]
案例二:获取 男性的员工信息
/*** 需求二:获取男性员工信息
*@return
*/
public static List genderFilter(Listlist){
List staffModelList=new ArrayList<>();for (int i = 0; i < list.size(); i++) {if (list.get(i).getGender() == '男') {
staffModelList.add(list.get(i));
}
}returnstaffModelList;
}/*** 测试
*@paramargs*/
public static voidmain(String[] args) {
System.out.println(genderFilter(staffModelArrayList));
}//测试
[StaffModel{name='张三', age=25, gender=男, salary=5000.0},
StaffModel{name='李飞飞', age=21, gender=男, salary=2000.0},
StaffModel{name='王晓非', age=24, gender=男, salary=6000.0}]
整体代码展示:
/*** 需求一:获取员工中 工资大于或五千的 员工信息
*@return
*/
public static List salaryFilter(Listlist){
List staffModelList=new ArrayList<>();for (int i = 0; i < list.size(); i++) {if (list.get(i).getSalary() >= 5000) {
staffModelList.add(list.get(i));
}
}returnstaffModelList;
}/*** 需求二:获取男性员工信息
*@return
*/
public static List genderFilter(Listlist){
List staffModelList=new ArrayList<>();for (int i = 0; i < list.size(); i++) {if (list.get(i).getGender() == '男') {
staffModelList.add(list.get(i));
}
}returnstaffModelList;
}
总结与思考
在传统方式中(如上例),面对不同的需求,我们需要 编写不同的方法(genderFilter()、genderFilter()),来实现,但是核心代码只有一句,
if (不同需求的条件(核心代码)) {
staffModelList.add(list.get(i));
}
若我们还有一个需求,获取年龄在25或25以上的员工信息,在传统方式中,我们无非就是再创建一个方法 copy 上面案例代码,更改 if(list.get(i).getAge()>=25) 这一句代码而已。
因为这一句代码,我们需要写很多重复性代码,如需求一 和 需求二,其实我们要改变的只有 if 条件判断而已。其他代码都不会做任何改动。
对于这样的代码,我们需要进行优化。只留核心,剔除其他。
优化方式一:设计模式
定义一个接口,由子类实现,完成过滤
/*** 过滤 策略 接口
*@authorAdministrator
*@param*/
public interface FilterStrategy{booleanfilter(T t);
}
创建一个子类,实现其接口,过滤规则由子类来定义
/*** 薪资过滤,
* 案例:过滤工资大于或等于 5000 的 员工
*@authorAdministrator*/
public class SalaryFilter implements FilterStrategy{
@Overridepublic booleanfilter(StaffModel staffModel) {return staffModel.getSalary()>=5000;
}
}
具体实现 案例一:普通的获取 工作大于或等于5000的 员工信息
/*** 员工过滤
*@paramlist 员工信息集
*@paramstrategy 过滤策略
*@return
*/
public static List staffFilter(List list,FilterStrategystrategy){
List staffModelList=new ArrayList<>();for (int i = 0; i < list.size(); i++) {if(strategy.filter(list.get(i))) {
staffModelList.add(list.get(i));
}
}returnstaffModelList;
}/*** 测试
*@paramargs*/
public static voidmain(String[] args) {//采用 薪资过滤策略
List staffModelList=staffFilter(staffModelArrayList,newSalaryFilter());
System.out.println(staffModelList);
}//测试结果
[StaffModel{name='张三', age=25, gender=男, salary=5000.0},
StaffModel{name='村花', age=25, gender=女, salary=5500.0},
StaffModel{name='牛妞妞', age=30, gender=女, salary=10000.0},
StaffModel{name='王晓非', age=24, gender=男, salary=6000.0}]
具体实现 案例二: 获取 男性的员工信息
/*** 案例二:获取员工中所有男性员工信息
*@authorAdministrator*/
public class GenderFilter implements FilterStrategy{
@Overridepublic booleanfilter(StaffModel staffModel) {return staffModel.getGender()=='男';
}
}/*** 测试
*@paramargs*/
public static voidmain(String[] args) {//采用 薪资过滤策略
List staffModelList=staffFilter(staffModelArrayList,newGenderFilter());
System.out.println(staffModelList);
}//运行结果
[StaffModel{name='张三', age=25, gender=男, salary=5000.0},
StaffModel{name='李飞飞', age=21, gender=男, salary=2000.0},
StaffModel{name='王晓非', age=24, gender=男, salary=6000.0}]
总结与思考:
这里采用的设计模式 为策略设计模式,与之前按照不同的需求来创建方法的传统方式相比,设计模式减少了冗余代码量,方法只有一个方法,只是需要按照不同的需求创建策略就行了。减少了冗余代码。只关注于核心。符合了OCP 原则。
案例二展示:
1:新建了一个过滤规则:性别过滤规则2:方法依旧是那个方法,只是main 方法 中的过滤规则变了。
/*** 案例二:获取员工中所有男性员工信息
*@authorAdministrator*/
public class GenderFilter implements FilterStrategy{
@Overridepublic booleanfilter(StaffModel staffModel) {return staffModel.getGender()=='男';
}
}/*** 员工过滤
*@paramlist 员工信息集
*@paramstrategy 过滤策略
*@return
*/
public static List staffFilter(List list,FilterStrategystrategy){
List staffModelList=new ArrayList<>();for (int i = 0; i < list.size(); i++) {if(strategy.filter(list.get(i))) {
staffModelList.add(list.get(i));
}
}returnstaffModelList;
}/*** 测试
*@paramargs*/
public static voidmain(String[] args) {//采用 性别过滤策略
List staffModelList=staffFilter(staffModelArrayList,newGenderFilter());
System.out.println(staffModelList);
}
优化方式二:匿名内部类
上一步方式的缺点:
上一步的优化方式是采用策略模式,那么他有什么缺点呢?设计模式肯定是没有缺点,这是再这里的案例中比较浪费,只要凡是增加一个需求,就必须创建一个类,编写相对应的过滤策略。之所以说浪费,是因为类代码少,又不得不创建一个新类(心累),显得很浪费而已。
所以这里又有一种优化方式,匿名内部类。
代码展示:
/*** 员工过滤
*@paramlist 员工信息集
*@paramstrategy 过滤策略
*@return
*/
public static List staffFilter(List list,FilterStrategystrategy){
List staffModelList=new ArrayList<>();for (int i = 0; i < list.size(); i++) {if(strategy.filter(list.get(i))) {
staffModelList.add(list.get(i));
}
}returnstaffModelList;
}/*** 测试 采用匿名内部类方式 进行过滤,过滤 年龄在 22 以上的员工信息
*@paramargs*/
public static voidmain(String[] args) {
List staffModelList = staffFilter(staffModelArrayList, new FilterStrategy() {
@Overridepublic booleanfilter(StaffModel staffModel) {return staffModel.getAge()>22;
}
});
System.out.println(staffModelList);
}//运行结果
[StaffModel{name='张三', age=25, gender=男, salary=5000.0},
StaffModel{name='村花', age=25, gender=女, salary=5500.0},
StaffModel{name='牛妞妞', age=30, gender=女, salary=10000.0},
StaffModel{name='王晓非', age=24, gender=男, salary=6000.0}]
总结与思考
对于上一种优化方式,不必再创建一个新的过滤器类。相对较而言,代码更少,更清晰。
优化方式三:Lambda 表达式
如果你的是 Idea 你会发现当你写 匿名内部类的时候,他已经提示你可以进行优化了
优化后的效果:代码已经缩短成了 两句代码 标志为 橙色 的就是我们需要的核心代码。
/*** 测试
*@paramargs*/
public static voidmain(String[] args) {
List staffModelList = staffFilter(staffModelArrayList, staffModel -> staffModel.getAge()>22);
System.out.println(staffModelList);
}//运行结果
[StaffModel{name='张三', age=25, gender=男, salary=5000.0},
StaffModel{name='村花', age=25, gender=女, salary=5500.0},
StaffModel{name='牛妞妞', age=30, gender=女, salary=10000.0},
StaffModel{name='王晓非', age=24, gender=男, salary=6000.0}]
再来一个需求,获取名称为 “张三” 的员工信息
/*** 测试
*@paramargs*/
public static voidmain(String[] args) {
List staffModelList = staffFilter(staffModelArrayList, staffModel -> staffModel.getName().equals("张三"));
System.out.println(staffModelList);
}//运行结果
[StaffModel{name='张三', age=25, gender=男, salary=5000.0}]
总结与思考
Lambda 表达式 优化了我们代码,使我们的代码看起来,更加简单和清晰。Lambda 表达式 的支持,需要 jdk1.8 以上(听说 jdk 已经 都11了)而我实际工作中用的还是 jdk8,对jdk 8的特性了解甚少。惭愧
优化方式四:Steam ApI
应该是 jdk8 新的特性,不是很了解,直接代码展示吧
public classLambdaTest {private static List staffModelArrayList=new ArrayList<>();static{
staffModelArrayList.add(new StaffModel("张三",25,'男',5000));
staffModelArrayList.add(new StaffModel("村花",25,'女',5500));
staffModelArrayList.add(new StaffModel("李飞飞",21,'男',2000));
staffModelArrayList.add(new StaffModel("牛妞妞",30,'女',10000));
staffModelArrayList.add(new StaffModel("王晓非",24,'男',6000));
}/*** 测试
*@paramargs*/
public static voidmain(String[] args) {
staffModelArrayList
.stream()
.filter((e)-> e.getAge()>22) //过滤 年龄 大于 22 的员工信息
.forEach(System.out::println); // 进行打印 类似 System.out.println
}
}//运行结果
StaffModel{name='张三', age=25, gender=男, salary=5000.0}
StaffModel{name='村花', age=25, gender=女, salary=5500.0}
StaffModel{name='牛妞妞', age=30, gender=女, salary=10000.0}
StaffModel{name='王晓非', age=24, gender=男, salary=6000.0}
除此之外还可以进行 向 sql 那样 分页(limit)
/*** 测试
*@paramargs*/
public static voidmain(String[] args) {
staffModelArrayList
.stream()
.filter((e)-> e.getAge()>22)//获取前两条数据
.limit(2)
.forEach(System.out::println);
}//运行结果
StaffModel{name='张三', age=25, gender=男, salary=5000.0}
StaffModel{name='村花', age=25, gender=女, salary=5500.0}
总结与思考
除此之外,还有hash 等,都有很好的优化处理。只能感叹,更新太快,工作太忙,太多东西学不完。