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