Java8在2014年3月发布,但是作为IT公司往往不是追求技术的新,而且追求技术的稳定。所以大多用的之前的版本。
下面是个人对Lambda表达式的一些认识:
1、lambda表达式最大的作用就是简化了我们的代码编写,使我们的代码更加的优雅。但是他并不能对于程序效率提升多少。
2、我个人感觉lambda表达式像是对内部类做了简化,在需要使用内部类的地方,不需要再去new
一个内部类了,仅仅只需要写内部类中最核心的代码就可以了。像是一个匿名方法一样,只用写参数和方法实现!
**需求:**现在有一个List集合
List
(emps employee
代表员工),现在要求筛选出该集合中的员工年龄大于40岁的所有员工!
Employee.java
public class Employee {
private int id;
private String name;
private int age;
private double salary;
}
我们首先想到的方法可能是,写一个方法,直接将 emps
集合进行遍历,然后判断年龄是否大于40岁,如果是则加入新的list集合中,遍历完成以后就将新的list集合返回即可。如下:
public List<Employee> filterEmployeeAge(List<Employee> emps){
List<Employee> list = new ArrayList<>();
for (Employee emp : emps) {
if(emp.getAge() <= 35){
list.add(emp);
}
}
return list;
}
这样做似乎没什么问题,但是现在又有一个新的需求了,现在需要过滤出薪水 salary
大于3000的所有员工,于是乎我们又需要编写一个通过员工薪水过滤的方法!如下:
public List<Employee> filterEmployeeSalary(List<Employee> emps){
List<Employee> list = new ArrayList<>();
for (Employee emp : emps) {
if(emp.getSalary() >= 5000){
list.add(emp);
}
}
return list;
}
这样做也没什么问题,但是现在又有一个新的需求了,现在需要过滤出员工id大于500的所有员工,于是我们又需要编写一个通过员工id过滤的方法!如下:
public List<Employee> filterEmployeeId(List<Employee> emps){
List<Employee> list = new ArrayList<>();
for (Employee emp : emps) {
if(emp.getId() >= 5000){
list.add(emp);
}
}
return list;
}
1、写着写着我们就开始发现问题了,所编写的几个方法中代码逻辑都一样,只有一行判断条件不同。我们写了很多的冗余代码。
2、我们可能还会通过员工姓名、生日、爱好、家庭地址、电话号码等等信息来过滤员工。那么我们就需要编写一个又一个的重复方法。这样就使得我们的代码变得冗余极其不优雅。所以我们需要进行改进。
通过策略设计模式来对我们的代码进行改进,首先我们定义一个过滤的方法,你需要通过什么条件进行过滤员工,那么将你的过滤策略通过方法的形参传入进来即可。在方法的内部会自动的根据你传入的策略进行过滤员工。
通过策略模式,我们知道我们首先需要去定义一个策略接口,每一个实现了该接口的类都是一个策略。如下:
@FunctionalInterface
public interface MyPredicate<T> {
public boolean test(T t);
}
现在我们要通过员工的id来过滤员工,过滤出员工id大于500的所有员工,所以我们要去定义一个策略实现类,继承自定义的接口MyPredicate。在实现类中覆写test方法去指定具体过滤策略。如下:
public class FilterEmployeeForId implements MyPredicate<Employee>{
//通过员工id过滤员工策略
@Override
public boolean test(Employee t) {
return t.id() > 500;
}
}
然后在编写一个过滤方法,通过传入的过滤策略来过滤员工。如下:
public List<Employee> filterEmployee(List<Employee> emps, MyPredicate<Employee> mp){
List<Employee> list = new ArrayList<>();
for (Employee employee : emps) {
if(mp.test(employee)){
list.add(employee);
}
}
return list;
}
在我们调用该方法来按条件过滤员工时,我们只需要传入实现了策略接口的具体实现类即可。如下:
@Test
public void test(){
List<Employee> list = filterEmployee(emps, new FilterEmployeeForId());
for (Employee employee : list) {
System.out.println(employee);
}
}
如果,现在又需要通过年龄过滤,过滤出年龄小于40岁的员工。那么我们只需要再定义一个具体策略类去实现策略接口MyPredicate即可。然后在调用的时候传入该策略实现类即可。不用再去写一个for循环遍历emps集合然后通过年龄做判断了。
但是如果这样做的话,每当我们要增加一个过滤需求,我们都需要自己去定义一个策略实现类然后实现策略接口,这样也显得比较麻烦!所以还需要进行改进!
我们仍然需要编写一个策略接口,但是当我们要通过具体xxx条件去过滤员工的时候,我们不用再自己去定义一个类然后实现他的策略方法了。我们可以直接通过匿名内部类完成。在匿名内部类中实现具体的策略!比如现在要过滤出员工id小于500的员工。如下:
@Test
public void test5(){
List<Employee> list = filterEmployee(emps, new MyPredicate<Employee>() {
//匿名内部类中实现具体的策略
@Override
public boolean test(Employee t) {
return t.getId() <= 500;
}
});
for (Employee employee : list) {
System.out.println(employee);
}
}
如果我们现在又要过滤出员工年龄小于40的所有员工,那么只需要改动匿名内部类中的过滤条件即可。但是这样的话,每一个不同的过滤条件仅仅是匿名内部类中的判断条件不同,其他的部分还是都是一样的(比如new MyPredicate() { xxx }),这样代码仍然不优雅,我们还需要做一定的修改。所以就引出了lambda表达式。
从方案2中我们看到了,每一个不同的过滤需求,其实只有匿名内部类中的一小部分改动,其他都是一样的。但是我们每次都要去手动创建匿名内部类。如果我们每次能只写过滤的核心条件就可完成员工的过滤多好呀!lambda表达式为我们做到了这一点。继方案2,使用lambda表达式,我们只需要传入核心的判断条件即可。如下:
public void test(){
List<Employee> list = filterEmployee(emps, (e) -> e.getId() <= 500);
list.forEach(System.out::println);
}
**说明:**在上面的代码中我们看到了,lambda表达式仅仅通过一行代码((e) -> e.getId() <= 500
)就表达了核心过滤条件。不用再去写匿名的内部策略类了。这里lambda表达式其实是对接口中的 test(xxx)
方法的一个实现。左边是该方法需要的参数,右边是该方法的方法体的具体内容。从上面的方案2和方案3可以看出,lambda表达式其实就是对使用匿名内部类的地方做了一个简化,我们只需要去写这个匿名内部类中的方法的具体逻辑即可,不用再去new 一个匿名内部类了,大大的简化了代码编写