最近在bibi看了一个视频,Up主一步步引出Lambda的方式看着很精彩,本文做个分享。
【背景】
如下,部门有十名员工,过滤"35岁以上","薪资高于5000" 的员工,怎么做呢?
public class Employee {
/**
* 姓名
*/
private String name;
/**
* 年龄
*/
private Integer age;
/**
* 薪水
*/
private Double salary;
/**
* 状态
*/
private Status status;
public Employee(String name, Integer age, Double salary){
this.name = name;
this.age = age;
this.salary = salary;
}
//getter and setter ignore
}
static List employees = Arrays.asList(
new Employee("张一",26,1226.66),
new Employee("王二",77,3456.66),
new Employee("张三",16,226.66),
new Employee("李四",31,666.66),
new Employee("王五",25,623.66),
new Employee("赵六",40,546.66),
new Employee("陈七",33,666.66),
new Employee("马八",55,999.66),
new Employee("刘九",29,666.66),
new Employee("周十",37,768.66)
);
【设计】
第一版:常规循环
1.方法过滤
class ForFilter{
//过滤年龄
public static List filterEmployeesAge(List list){
List emps = new ArrayList<>();
for(Employee emp : list){
if(emp.getAge() >= 35){
emps.add(emp);
}
}
return emps;
}
//过滤薪资
public static List filterEmployeesSalary(List list){
List emps = new ArrayList<>();
for(Employee emp : list){
if(emp.getSalary() >= 5000){
emps.add(emp);
}
}
return emps;
}
}
2.调用:
public static void main(String[] args) {
//遍历过滤 年龄
List list = filterEmployeesAge(employees);
for(Employee employee : list){
System.out.println(employee);
}
//遍历过滤 薪资
List list1 = filterEmployeesSalary(employees);
for(Employee employee : list1){
System.out.println(employee);
}
}
分析:
1.优点:无
2.缺点:新增过滤条件,需添加新的"filterBy"方法,该方法代码重复度高大80%。
第二版:策略模式
1.策略接口
public interface MyPredicate {
/**
* 过滤条件
*/
public boolean test(T t);
}
2.策略类,实现MyPredicate接口
public class FilterEmployeeByAge implements MyPredicate {
/**
* 年龄大于35岁
*/
@Override
public boolean test(Employee t) {
return t.getAge() >= 35;
}
}
public class FilterEmployeeBySalary implements MyPredicate {
/**
* 薪资大于5000
*/
@Override
public boolean test(Employee t) {
return t.getSalary() > 5000;
}
}
3.调用
public static void main(String[] args) {
//策略模式 - 过滤年龄
List list2 = filterEmpByStrategy(employees, new FilterEmployeeByAge());
for(Employee employee : list2){
System.out.println(employee);
}
//策略模式 - 过滤薪资
List list3 = filterEmpByStrategy(employees, new FilterEmployeeBySalary());
for(Employee employee : list3){
System.out.println(employee);
}
}
/**
* 根据策略过滤
*/
public static List filterEmpByStrategy(List list, MyPredicate mp){
List emps = new ArrayList<>();
for(Employee employee : list){
if(mp.test(employee)){
emps.add(employee);
}
}
return emps;
}
策略模式,分析:
1.优点:新增需求时,虽新增接口实现类,但利用多态,重复代码大量减少。
2.缺点:虽减少了重复代码,新增需求时,接口实现类略显臃肿
第三版:策略+匿名内部类
1.策略接口
public interface MyPredicate {
/**
* 过滤条件
*/
public boolean test(T t);
}
2.调用
public static void main(String[] args) {
//调用过滤器时,以匿名内部类形式,实现过滤接口
List list4 = filterEmpByStrategy(employees, new MyPredicate() {
@Override
public boolean test(Employee employee) {
return employee.getSalary() < 5000;
}
});
for(Employee employee : list4){
System.out.println(employee);
}
}
/**
* 过滤器
*/
public static List filterEmpByStrategy(List list, MyPredicate mp){
List emps = new ArrayList<>();
for(Employee employee : list){
if(mp.test(employee)){
emps.add(employee);
}
}
return emps;
}
分析:
1.优点: 相比“策略模式”,去掉接口实现类
2.缺点:匿名内部类编码时,又产生了部分冗余代码
第四版:Lambda
1.保留“MyPredicate”过滤接口、“filterEmpByStrategy”过滤器
2.调用
public static void main(String[] args) {
List list = filterEmpByStrategy(employees, (e) -> e.getSalary() <= 5000);
list.forEach(System.out::println);
}
分析:
1.优点:几乎零重复;只定义接口,无需实现类 或 匿名实现类。
2.思考:fiterEmpStrategy() 及MyPredicate接口,是否可简化?
第五版:Stream Api
public static void main(String[] args) {
employees.stream()
.filter((e) -> e.getSalary() <= 5000)
.limit(2)
.forEach(System.out::println);
}
分析:
1.优点:简洁;无需接口、实现类、过滤器等
2.缺点:无
【总结】
刚入门的人把编程当理科,学习中的人当工科,但最终编程是文科,就像写文章画画,是作者思想的呈现。