1、什么是lambda Lambda表达式是一个匿名函数,我们可以这样理解Lambda表达式:Lambda是一段可以传递的代码(能够做到将代码像数据一样进行传递)
例如有一个需求:筛选一个班级中分数大于80的学生
2、硬编码
传统方式中我们要怎样实现这个需求呢?一般是以下这样:
public class Student implements Serializable{ private static final long serialVersionUID = 3521611983124991686L; private String name; private Integer age; private Double score; public String getName() { return name; } public Student setName(String name) { this.name = name; return this; } public Integer getAge() { return age; } public Student setAge(Integer age) { this.age = age; return this; } public Double getScore() { return score; } public Student setScore(Double score) { this.score = score; return this; } public static Student builder(){ return new Student(); } @Override public String toString() { return "Student{" + "name='" + name + '\'' + ", age=" + age + ", score=" + score + '}'; } } List<Student> students = Arrays.asList( Student.builder().setAge(18).setName("张三").setScore(79D), Student.builder().setAge(16).setName("李四").setScore(98D), Student.builder().setAge(20).setName("王五").setScore(72D), Student.builder().setAge(17).setName("赵六").setScore(59D), Student.builder().setAge(19).setName("Bob").setScore(84D)); List<Student> simpleStudents = new ArrayList<>(); for (Student student : students){ if (student.getScore() > 80){ simpleStudents.add(student); } }得到结果:
此时如果我们再增加一个需求:筛选年龄小于18的学生,那我们就得再加一个for循环,如下:
simpleStudents = new ArrayList<>(); for (Student student : students){ if (student.getAge() < 18){ simpleStudents.add(student); } }相信不少人看到这样的代码都会觉得别扭,差别只有一行,如果业务更复杂一点,我们还会冗余更多,拓展起来也很麻烦,这个时候我们可以使用设计模式,使业务代码更清爽一点。
3、策略模式
我们定义好抽象策略类、具体策略类,以及持有策略引用的上下文
public interface StudentFilter { boolean filter(Student student); } public class StudentAgeFilter implements StudentFilter { @Override public boolean filter(Student student) { if (student.getAge() < 18){ return true; } return false; } } public class StudentScoreFilter implements StudentFilter { @Override public boolean filter(Student student) { if (student.getScore() > 80){ return true; } return false; } } public class StudentFilterContext { public static List<Student> filterContext(List<Student> originStudents, StudentFilter studentFilter){ List<Student> filterList = new ArrayList<>(originStudents.size()); for (Student student : originStudents){ if (studentFilter.filter(student)){ filterList.add(student); } } return filterList; } }这样我们在业务代码中实现上述逻辑就只需要下面几行代码了,而且如果再增加新的需求,就只需要增加具体策略即可。
List<Student> strategyStudents = StudentFilterContext.filterContext(students, new StudentScoreFilter()); strategyStudents = StudentFilterContext.filterContext(students, new StudentAgeFilter());4、匿名内部类
虽然使用策略模式我们的业务代码简洁了很多,也增强了拓展性,但是每增加一个策略,都需要新建一个具体的策略类,如果需要抽象的策略并不是很复杂的话这样就显得有些过度设计了。我们尝试一下使用内部类来解决这个问题:
List<Student> filterStudents = StudentFilterContext.filterContext(students, new StudentFilter() { @Override public boolean filter(Student student) { return student.getScore() > 80; } });5、lambda表达式
虽然省略了新建策略类,但是又回去了之前的问题,业务代码冗余,实际上有用的只有student.getScore() > 80,这时候我们就可以使用lambda表达式来优化这段代码了:
List<Student> lambdaStudents = StudentFilterContext.filterContext(students, (s) -> s.getScore() > 80);可以看到我们将原有的匿名内部类直接替换成了 (s) -> s.getScore() > 80,这是因为lambda本质上就是对接口的实现,s就是接口实现方法中的参数列表(对应中filter中的参数),而s.getScore() > 80就是方法中的实现(对应filter中的 return student.getScore > 80)。
6、lambda表达式的语法
Lambda表达式在Java语言中引入了 “->” 操作符, “->” 操作符被称为Lambda表达式的操作符或者箭头操作符,它将Lambda表达式分为两部分: 左侧部分指定了Lambda表达式需要的所有参数。 Lambda表达式本质上是对接口的实现,Lambda表达式的参数列表本质上对应着接口中方法的参数列表。 右侧部分指定了Lambda体,即Lambda表达式要执行的功能。
7、函数式接口
lambda表达式要求实现的接口必须是函数式接口,而函数式接口接口就是只包含一个抽象方法的接口,我们可以在接口上使用@FunctionalInterface 注解来检查标注一个接口是否是函数式接口。
在java中有很多这样的函数式接口,以下是我们最常用的四大函数式接口:
四大函数式接口 接口参数类型返回值类型适用场景ConsumerT无对类型为T的对象使用操作Supplier无T无参数,返回一个类型为T的对象Function<T,R>TR传入一个类型为T的对象,并返回一个R类型的对象PredicateTboolean判断一个类型为T的对象是否满足条件,并返回一个布尔值
参考技术博客:冰河技术