简介
Lambda是Java8中支持的一种新的语法格式,Lambda 是一个匿名函数,我们可以把 Lambda 表达式理解为一段可以传递的代码(将代码像数据一样进行传递)。使用Lambda表达式可以写出更简洁、更灵活的代码。作为一种更紧凑的代码风格,使Java的语言表达能力得到了提升。
示例
需求:查询公司年龄大于35岁的员工信息
实现方式一
:提供一个专门的过滤方法
public class TestMain {
//数据
List<Employee> employees = new ArrayList<Employee>(Arrays.asList(
new Employee("zhangsan", 24, 5050.00),
new Employee("lisi", 58, 6666.00),
new Employee("wangwu", 32, 3333.00),
new Employee("xueliu", 43, 2222.00),
new Employee("tianqi", 28, 7777.00),
new Employee("maer", 36, 8888.00)
));
/**
* 过滤年龄超过35岁的员工
* @param employees
* @return
*/
public List<Employee> filterEmpByAge(List<Employee> employees){
List<Employee> emps = new ArrayList<>();
for(Employee emp : employees)
if(emp.getAge() > 35)
emps.add(emp);
return emps;
}
@Test
public void test1(){
//调用方法获取员工中年龄大于35的员工信息
List<Employee> filterEmpByAge = filterEmpByAge(employees);
for (Employee employee : filterEmpByAge) {
System.out.println(employee);
}
}
}
如果此时需求有变动,让查询工资大于5000的员工,则需要再专门提供一个使用工资进行过滤的方法:
/**
* 工资超过5000的员工
* @param employees
* @return
*/
public List<Employee> filterEmpBySalary(List<Employee> employees){
List<Employee> emps = new ArrayList<>();
for(Employee emp : employees)
if(emp.getSalary() > 5000)
emps.add(emp);
return emps;
}
而需求是多变的,这样的话就可能会有很多类似的方法,而这些方法中只有一处不同,那就是过滤条件,其他地方完全一样,很明显这样会有很多的代码冗余。
实现方式二
:策略设计模式
1、定义一个过滤的接口
public interface PredicateRule<T> {
/**
* 返回符合条件的t
*
* @param t
* @return
*/
public boolean test(T t);
}
2、按照条件提供两个该接口的实现:
/**
* 年龄大于35
*/
public class AgePredicateRule implements PredicateRule<Employee> {
@Override
public boolean test(Employee t) {
return t.getAge() > 35;
}
}
/**
* 工资大于5000
*/
public class SalaryPredicateRule implements PredicateRule<Employee> {
@Override
public boolean test(Employee t) {
return t.getSalary() > 5000;
}
}
3、提供一个公共的过滤方法:该方法会根据传入的PredicateRule的具体实现进行过滤
/**
* 统一的过滤方法:会根据传入的PredicateRule的实现进行过滤
*
* @param emps
* @param rule
* @return
*/
public List<Employee> filterEmpByRule(List<Employee> emps, PredicateRule<Employee> rule) {
List<Employee> employees = new ArrayList<>();
for (Employee employee : emps)
if (rule.test(employee))
employees.add(employee);
return employees;
}
4、使用:此时传入的是AgePredicateRule,则会过滤年龄超过35岁的员工
public void test2() {
//此时传入的是AgePredicateRule,则会过滤年龄超过35岁的员工
List<Employee> filterEmpByRule = filterEmpByRule(employees, new AgePredicateRule());
for (Employee employee : filterEmpByRule) {
System.out.println(employee);
}
}
实现方式三
:匿名内部类,方式二中每增加一个查询条件都需要实现一次过滤接口,而且实现的方式中也只有一行代码是不同的,我们可以使用内名内部类的方式避免创建冗余的接口实现
/**
* 统一的过滤方法:会根据传入的PredicateRule的实现进行过滤
*
* @param emps
* @param rule
* @return
*/
public List<Employee> filterEmpByRule(List<Employee> emps, PredicateRule<Employee> rule) {
List<Employee> employees = new ArrayList<>();
for (Employee employee : emps)
if (rule.test(employee))
employees.add(employee);
return employees;
}
@Test
public void test3() {
//使用匿名内部类
List<Employee> filterEmpByRule = filterEmpByRule(employees, new PredicateRule<Employee>() {
@Override
public boolean test(Employee t) {
// 过滤年龄大于35岁的员工
return t.getAge() > 35;
}
});
for (Employee employee : filterEmpByRule) {
System.out.println(employee);
}
}
这样虽然避免了频繁创建接口的实现导致的代码冗余,但影响了代码的可读性,且从一定程度上代码还是有冗余,因为过滤的核心代码只是条件而已
鉴于以上种种弊端,Java8提供了Lambda表达式
/**
* 统一的过滤方法:会根据传入的PredicateRule的实现进行过滤
*
* @param emps
* @param rule
* @return
*/
public List<Employee> filterEmpByRule(List<Employee> emps, PredicateRule<Employee> rule) {
List<Employee> employees = new ArrayList<>();
for (Employee employee : emps)
if (rule.test(employee))
employees.add(employee);
return employees;
}
@Test
public void test4() {
List<Employee> filterEmpByRule = filterEmpByRule(employees, (e) -> e.getAge() > 35);
filterEmpByRule.forEach(System.out::println);
}
Lambda表达式实际上是一个匿名函数,该匿名函数会根据方法的入参自动推断出你要调用的方法,比如此时调用方法filterEmpByRule(List list,PredicateRule rule),我们在第二个参数的位置使用了Lambda表达式,那么Java8就会推断出来你要调用的是PredicateRule接口中的方法,Lambda表达式的小括号()中的内容表示调用该方法时传入的参数,箭头->后面的代码则表示方法的方法体,因此PredicateRule 接口只能定义一个抽象方法(这样的接口称为函数接口),否则Lambda在推断时将会出错,入参的类型则由泛型定义。
可以看出使用Lambda表达式只需要写关键的代码即可,会大大的节省代码量。
还可以使用Stream API作进一步精简:这样连接口和公共方法都不需要提供了
public class TestMain {
// 数据
List<Employee> employees = new ArrayList<Employee>(Arrays.asList(new Employee("zhangsan", 24, 5050.00),
new Employee("lisi", 58, 6666.00), new Employee("wangwu", 32, 3333.00), new Employee("xueliu", 43, 2222.00),
new Employee("tianqi", 28, 7777.00), new Employee("maer", 36, 8888.00)));
@Test
public void test6() {
employees.stream().filter(e -> e.getAge() > 35).forEach(System.out::println);
//取过滤后的前两个
employees.stream().filter(e -> e.getAge() > 35).limit(2).forEach(System.out::println);
//获取集合中每个员工的名字
employees.stream().map(Employee::getName).forEach(System.out::println);
}
}