匿名类为代码简化提供了一种方式。
lamada表达式在匿名类之上,实现了进一步的简化,但它要求接口的抽象方法只有一个!
因为lamada的出现,有了"函数式接口"的概念
假设现在有一个场景:需要对一个元素为person的集合list,进行筛选,对筛选后的集合进行转换,最后对转换后的集合执行某种统一操作:
public class Demo01 {
public static void main(String[] args) {
ArrayList<Person> persons = new ArrayList<>();
persons.add(new Person());
// lambda表达式 p -> true,简化了匿名类
// 同时将其赋值给func,体现了函数式编程风格
// 而类型是接口, 所以称"函数式接口"
checkPerson func = p -> true;
printPersons(persons, func);
// 简约版——lambda表达式
printPersons(persons, p -> true);
// 匿名类
printPersons(persons, new checkPerson() {
@Override
public boolean check(Person p) {
return true;
}
});
}
private static void printPersons(List<Person> persons, checkPerson checkPerson) {
for (Person person : persons) {
if(checkPerson.check(person)){
System.out.println(person.getEmail());
}
}
}
}
总结:
1.你可以完全理解为,lambda表达式是为了进一步简化匿名类,只不过在简化的过程中,"函数式编程"、"函数式接口"这类概念应运而生;
2.看起来,是将一个函数传给了一个变量,但这个变量依然是接口类型,实质并不是函数,只是代码风格变得简单了;
上述printPersons看起来扩展性并不好,现在的处理方式是简单打印,如果替换成更复杂的操作,printPersons的逻辑显然需要重新修改,故引入下面的方式:
public class Demo02 {
public static void main(String[] args) {
ArrayList<Person> peoples = new ArrayList<>();
peoples.add(new Person());
printPersons(peoples,
person -> true,
Person::getEmail,
System.out::println);
}
private static <T, Y> void printPersons(List<T> persons,
Predicate<T> filter,
Function<T, Y> mapper,
Consumer<Y> consumer) {
for (T person : persons) {
if(filter.test(person)){
Y email = mapper.apply(person);
consumer.accept(email);
}
}
}
}
说明:
1.两种方式运行结果必然一致,自行测试;
2.printPersons的逻辑可以任意变更,但方法内的任何一行代码都不需要改动;
3.printPersons已经被设计得更加通用,根据长远的业务要求或其他要求,抽象出过滤-转换-处理三个层次;
4.Predicate提供test函数,通过断言,实现过滤;
5.Function提供apply函数,实现转换;
6.Consumer用来消费数据,不需返回值,可以用来执行一些处理操作;
更进一步的简化:
public class Demo03 {
public static void main(String[] args) {
ArrayList<Person> peoples = new ArrayList<>();
peoples.add(new Person());
peoples.stream().filter(person -> true).map(Person::getEmail).forEach(System.out::println);
}
}
总之,对于集合类数据,需要做处理时,首选stream+lambda的方式来完成。