JDK8--02:为什么要使用lambda
lambda是一个匿名函数,我们可以把lambda理解为一个可以传递的代码(将代码像数据一样传递),可以写出更简洁更灵活的代码。
首先看一下原来的匿名内部类实现方式(以比较器为例)
//原来的匿名内部类实现方式 public void test1(){ //定义一个匿名内部类comparator Comparator<Integer> comparator = new Comparator<Integer>() { @Override public int compare(Integer o1, Integer o2) { return Integer.compare(o1,o2); } }; //将匿名内部类作为对象传入 TreeSet<Integer> treeSet = new TreeSet<>(comparator); }
以上代码实际上实际有用的代码只有两行(第7行),但是却需要写这么多代码,非常痛苦,lambda就很好的解决了该问题。
lambda实现方式
//lambda表达式实现 public void test2(){ //lambda表达式 Comparator<Integer> comparator = (x,y)->Integer.compare(x,y); //将匿名内部类作为对象传入 TreeSet<Integer> treeSet = new TreeSet<>(comparator); }
通过以上可以看到,原来的多行代码,变为了一行实现,代码量大大减少,但是,如果只是这样的一个结论,显然不能说服人(匿名内部类我直接就可以一键生成,对开发来说影响并不是很大,反而要学习一个新的语法,这种投入产出比不太大)
所以再举一个例子来说明lambda的优势:
需求1:获取公司中年龄大于35岁的员工
先创建实体类
package com.example.jdk8demo.lambda; import lombok.AllArgsConstructor; import lombok.Data; import lombok.RequiredArgsConstructor; import lombok.ToString; @Data @RequiredArgsConstructor @AllArgsConstructor @ToString public class Employer { private String name; private Integer age; private double salary; }
为了方便演示,就不再进行数据库操作,直接模拟一个员工集合
/** * 模拟员工集合 */ private List<Employer> list = Arrays.asList( new Employer("张三",18,2222.22), new Employer("李四",32,3333.33), new Employer("王五",52,4444.44), new Employer("赵六",44,5555.55), new Employer("田七",8,4235.32), new Employer("牛八",28,3256.52) );
然后就是实现逻辑代码,我们一般会直接定义一个方法去实现,如下代码所示
/** * 查询年龄大于35岁的员工 * @return */ public List<Employer> getEmpolyerByAge(){ List<Employer> employerList = new ArrayList<>(); for (Employer employer : list){ if(employer.getAge() > 35){ employerList.add(employer); } } return employerList; }
那么如果此时,又来了一个需求
需求2:查询工资大于4000的员工
我们还需要再写一个实现方法
/** * 查询工资大于4000的员工 * @return */ public List<Employer> getEmpolyerBySalary(){ List<Employer> employerList = new ArrayList<>(); for (Employer employer : list){ if(employer.getSalary() > 4000){ employerList.add(employer); } } return employerList; }
可以发现,两个方法中,只有 employer.getAge() > 35 和 employer.getSalary() > 4000 是不同的,其余的代码都一样,如果后续还有新的类似需求增加,呢么冗余代码会越来越多,因此我们就需要对代码进行优化。
优化方案一:使用策略模式
一般情况下,对于这种冗余代码,我们的优化会使用策略模式进行优化
首先,先创建一个接口
package com.example.jdk8demo.lambda; public interface EmpolyerService<T> { boolean filter(T t); }
然后针对不同的需求,做不同的实现类
第一个实现类是针对查询年龄大于35的员工
package com.example.jdk8demo.lambda; public class EmpolyerImplByage implements EmpolyerService<Employer> { @Override public boolean filter(Employer employer) { return employer.getAge() > 35; } }
第二个实现类是针对查询公司大于4000的员工
package com.example.jdk8demo.lambda; public class EmpolyerImplBySalary implements EmpolyerService<Employer> { @Override public boolean filter(Employer employer) { return employer.getSalary() > 4000; } }
然后就是使用策略模式进行查询,方法的入参是接口的实现类,然后根据实现类中对接口方法的不同实现进行不同的处理。
/** * 使用策略模式查询员工信息 * @param empolyerService * @return */ public List<Employer> getEmpolyerList(EmpolyerService<Employer> empolyerService){ List<Employer> employerList = new ArrayList<>(); for (Employer employer : list){ if(empolyerService.filter(employer)){ employerList.add(employer); } } return employerList; }
最后所有需求都统一调用新增的策略模式方法,具体的入参就是接口具体的实现类
/** * 优化一:采用策略模式 */ public void test5(){ List<Employer> employerList = getEmpolyerList(new EmpolyerImplByage()); for (Employer employer : employerList){ log.info(employer.toString()); } log.info("============================================="); employerList = getEmpolyerList(new EmpolyerImplBySalary()); for (Employer employer : employerList){ log.info(employer.toString()); } }
这种优化也有不好的地方,就是一个需求就要创建一个实现类,随着需求的增加,实现类会越来越多,所以可以进一步进行优化
优化方案二:使用匿名内部类
由于采用策略模式,一个需求就需要创建一个实现类,导致文件增多,因此可以将策略模式改为使用匿名内部类,使用匿名内部类,仍然需要上述的过滤接口,但是无需再使用接口的实现类
/** * 优化方式二:匿名内部类 */ public void test6(){ List<Employer> employerList = getEmpolyerList(new EmpolyerService<Employer>() { @Override public boolean filter(Employer employer) { return employer.getAge() > 20; } }); for (Employer employer : employerList){ log.info(employer.toString()); } log.info("============================================="); employerList = getEmpolyerList(new EmpolyerService<Employer>() { @Override public boolean filter(Employer employer) { return employer.getSalary() > 3000; } }); for (Employer employer : employerList){ log.info(employer.toString()); } }
由此已经对应了本文刚开始的时候,匿名内部类中有用的代码实际就一行,但是缺需要写大量其他无用的代码,因此可以使用lambda进行优化。
优化方案三:使用lambda
/** * 优化方式七:lambda表达式 */ public void test7(){ LambdaTest lambdaTest = new LambdaTest(); List<Employer> employerList = lambdaTest.getEmpolyerList((e) -> e.getAge()>30); employerList.forEach(System.out::println); log.info("============================================="); employerList = lambdaTest.getEmpolyerList((e)->e.getSalary()>3000); employerList.forEach(System.out::println); }
可以发现,使用lambda表达式后,代码简单、简洁。到此处,为什么要使用lambda已经描述完毕,但是对于java8来说,还有更简洁的优化方式,就是Stream流。
优化方式四:Stream流
此种实现,不需要像前三种优化方式一样新建接口,这里直接使用流式过滤即可。
/** * 使用StreamAPI查询员工信息 */ public void test8(){ list.stream()//流式处理 .filter((e)->e.getSalary()>2000)//过滤出工资大于2000的员工 .filter((e)->e.getAge()>30)//过滤出年龄大于30的员工 .limit(2)//只查询前两条 .forEach(System.out::println);//循环打印 }
-----------------------------------------------------------
---------------------------------------------
朦胧的夜 留笔~~