一、为什么要使用 Lambda 表达式
简单来说,Lambda 是一个匿名函数,我们可以把 Lambda 表达式理解为是一段可以传递的代码(可以像数据一样进行传递)。因此我们使用 Lambda 表达式就可以写出更简洁、更灵活的代码。
下面一起来探寻下为什么要使用 Lambda 表达式:
1、假如我现在想比较两个数的大小,那么我可以通过下面的方式去实现:
@Test
public void test1() {
Comparator<Integer> com = new Comparator<Integer>() {
@Override
public int compare(Integer o1, Integer o2) {
return Integer.compare(o1, o2);
}
};
List<Integer> list = Arrays.asList(3,5,2);
Collections.sort(list,com);
System.out.println(list);
}
@Test
public void test2() {
Comparator<Integer> com = (x, y) -> Integer.compare(x, y);
List<Integer> list = Arrays.asList(3,5,2);
Collections.sort(list,com);
}
上面实现方式,第一种就是通过匿名内部类的方式去实现,第二种是通过 Lambda 方式去实现,我们可以发现使用 Lambda 的方式明显比匿名内部类的方式高效的很多。
2、假设我现在有个需求,想获取当前公司中员工年龄大于35的员工信息,传统的方法我们应该是这么做的:
List<Employee> employees = Arrays.asList(new Employee("张三", 24, 3200),
new Employee("李四", 32, 1300),
new Employee("王五", 60, 7000),
new Employee("赵六", 74, 8500),
new Employee("田七", 18, 2700));
public List<Employee> filterEmployee(List<Employee> list) {
List<Employee> emps = new ArrayList<Employee>();
for (Employee employee : list) {
if (employee.getAge() > 35) {
emps.add(employee);
}
}
return emps;
}
public List<Employee> filterEmployee2(List<Employee> list) {
List<Employee> emps = new ArrayList<Employee>();
for (Employee employee : list) {
if (employee.getSalary() > 5000) {
emps.add(employee);
}
}
return emps;
}
对比上面写的两个方法,我们可以发现, 第二个方法和第一个方法就一行代码不同,存在大量代码冗余。既然存在代码冗余,那么我们就要对代码进行优化:
优化方式一:
public interface MyPredict<T> {
public boolean test(T t);
}
public List<Employee> filterEmployee(List<Employee> emps, MyPredict<Employee> mp) {
List<Employee> emplist = new ArrayList<Employee>();
for (Employee employee : emps) {
if (mp.test(employee)) {
emplist.add(employee);
}
}
return emps;
}
@Test
public void test4() {
List<Employee> list = filterEmployee(employees, new FilterEmployeeByAge());
System.out.println("-----------------");
List<Employee> list2 = filterEmployee(employees, new FilterEmployeeBySalary());
}
上面的这种优化方式,你会发现如果你有很多需求的话,你就要新建很多的实现类,而这些实现类里面就一个方法,这样比较不划算,所以我们就考虑到使用匿名内部类的方式。所以第二种优化方案:
优化方式二:
@Test
public void test5() {
List<Employee> list = filterEmployee(employees, new MyPredict<Employee>() {
@Override
public boolean test(Employee t) {
return t.getSalary() < 6000;
}
});
}
直接使用匿名内部类的方式,避免创建很多的类。在匿名内部类的基础上,我们可以进一步使用 Lambda 表达式,所以第三种优化方案:
优化方式三:
@Test
public void test6() {
List<Employee> list = filterEmployee(employees, (e) -> e.getSalary() > 5000);
}
使用 Lambda 表达式一行代码解决。综上来看,使用 Lambda 表达式确实可以帮助我们写出更灵活,更简洁的代码。
二、Lambda 表达式语法
Java8 中引入了一个新的操作符 "->",该操作符称为箭头操作符或Lambda操作符,箭头操作符将 Lambda 表达式拆分成两部分:
所谓的 Lambda 表达式其实就是对接口的实现,之前我们用匿名内部类去实现接口,现在我们就可以使用 Lambda 表达式去实现接口。
关于左侧和右侧到底写什么在说下: 接口中它是有一个抽象方法的,所谓的 Lambda 表达式左侧的参数列表对应的就是你接口中抽象方法的参数列表,相应的箭头操作符的右侧,就是你对接口中抽象方法的实现。
那假设接口中有多个抽象方法,Lambda 表达式到底实现哪一个呢?
答:实际上 Lambda 表达式需要函数式接口的支持。所谓的函数式接口就是你这个接口中只有一个抽象方法的接口。
Lambda 表达式语法格式:
语法格式一:无参数,无返回值
例:
() -> System.out.println("hello world");
@Test
public void test1() {
Runnable runnable = new Runnable() {
@Override
public void run() {
System.out.println("hello world");
}
};
runnable.run();
Runnable run = () -> System.out.println("hello");
run.run();
}
语法格式二:有一个参数,并且无返回值
例:
(x) -> System.out.println(x);
语法格式三:若只有一个参数,小括号可以省略不写
例:
x -> System.out.println(x);
@Test
public void test2() {
Consumer<String> con = (x) -> System.out.println(x);
con.accept("我是 hepingfly");
}
语法格式四:有两个以上的参数,有返回值,并且 Lambda 体中有多条语句
例:
Comparator<Integer> com = (x,y) -> {
System.out.println("函数式接口");
return Integer.compare(x, y);
};
@Test
public void test3() {
Comparator<Integer> com = (x,y) -> {
System.out.println("欢迎关注 hepingfly");
return Integer.compare(x, y);
};
}
语法格式五:若 Lambda 体中只有一条语句,return 和大括号都可以省略不写
例:
Comparator<Integer> com = (x,y) -> Integer.compare(x, y);
语法格式六:Lambda 表达式的参数列表的数据类型可以省略不写,因为 JVM 编译器通过上下文推断出数据类型,即 "类型推断"
例:
(Integer x, Integer y) -> Integer.compare(x, y);
因为我左边参数列表写的是接口中抽象方法的参数列表,像上面 Comparator 接口,我在泛型中已经指定参数是 Integer 类型的,所以接口的抽象方法中参数列表肯定是 Integer 类型的。
@Test
public void test4() {
Comparator<Integer> com = (x,y) -> Integer.compare(x, y);
}
注意:
评论