Java函数式编程(1):Lambda表达式(1)

时间:2022-11-03 11:23:14

您好,我是湘王,这是我的51CTO博客,欢迎您来,欢迎您再来~


Java在其技术发展周期中经历过几次比较重要的变化,如果不是这几次比较重要的变化,恐怕不会有现在这样的江湖地位。个人看来,至少有两次,一是2010~2011年兴起的移动应用开发,Android的出现,让Java狠狠地出了次风头。再就是2014年发布的Java8,这个版本也是Java8之前和后续所有版本的一个分水岭。尽管在Java8之后出现了更多的版本,也加入了很多的功能,但从改变上来上,Java8可以说是一次脱胎换骨的变化,而原因就在于它引入了函数式编程(这个没有绝对的正确与否,仅是个人之间)。

Java码农都知道,虽然都学过集合、I/O、多线程、泛型、抽象类、注解、反射等若干高大上的内容,但实际上真正在工作中最头疼、用得最多的却是集合操作。这也很好理解:业务数据就是业务的血肉,而对数据的读取、存储、传输等操作,会业务规则变得非常麻烦。

比如像单纯数字列表的筛选、排序、去重,对于JDK7及以下版本来说会比较麻烦,类似[1, 3, 7, 2, 10, 13, 11, 9, 22]这样的列表,即使是比较简单的冒泡排序,也至少需要一个嵌套循环。

再就是含有复杂嵌套对象的列表,其查询、排序、筛选等需求,如果使用目前的Java集合类库,实现起来会异常麻烦,例如,假如现在需要实现让不同公司的员工举行联谊,将信息登记在一个列表上,然后选出未婚员工,解决员工单身问题,且将全部的员工按年龄从小到大排序,如果要你来实现,该怎么做?这其实就是一个列表数据筛选的问题,List<Company<Employee>>这样的集合数据进行排序、汇总等操作,会非常麻烦。

也就是假如有下面的类和对象:

public class Company<T> {
public enum Type { BIG, SMALL };
private String name;
private Type type;
private List<T> employees;

public Company(final String name, final Type type, final List<T> employees) {
super();
this.name = name;
this.type = type;
this.employees = employees;
}

public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Type getType() {
return type;
}
public void setType(Type type) {
this.type = type;
}
public List<T> getEmployees() {
return employees;
}
public void setEmployees(List<T> employees) {
this.employees = employees;
}
@Override
public String toString() {
return this.name;
}
}



public class Employee {
public enum Type { MANAGER, SELLER, OFFICER };
private String name;
private String genger;
private Integer age;
private boolean married;
private Type type;
public Employee(final String name, final String genger, final Integer age, final boolean married, final Type type) {
super();
this.name = name;
this.genger = genger;
this.age = age;
this.married = married;
this.type = type;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getGenger() {
return genger;
}
public void setGenger(String genger) {
this.genger = genger;
}
public Integer getAge() {
return age;
}
public void setAge(Integer age) {
this.age = age;
}
public boolean isMarried() {
return married;
}
public void setMarried(boolean married) {
this.married = married;
}
public Type getType() {
return type;
}
public void setType(Type type) {
this.type = type;
}
@Override
public String toString() {
return this.name + "(" + this.genger + ")-" + this.age;
}
}



public static void main(String[] args) {
// 创造数据
List<Company<Employee>> list = new ArrayList<>();
List<Employee> employees = Arrays.asList(
new Employee("张勇", "男", 28, true, Employee.Type.MANAGER),
new Employee("李强", "男", 22, false, Employee.Type.SELLER),
new Employee("王武", "男", 32, false, Employee.Type.SELLER),
new Employee("梅丽", "女", 26, true, Employee.Type.OFFICER),
new Employee("郑帅", "男", 29, false, Employee.Type.OFFICER),
new Employee("曾美", "女", 27, true, Employee.Type.SELLER),
new Employee("郝俊", "男", 22, true, Employee.Type.SELLER),
new Employee("方圆", "女", 24, false, Employee.Type.SELLER)
);
Company<Employee> moubao = new Company<Employee>("某宝", Company.Type.BIG, employees);

employees = Arrays.asList(
new Employee("吴琼", "女", 27, true, Employee.Type.SELLER),
new Employee("陈辰", "女", 20, false, Employee.Type.OFFICER),
new Employee("刘能", "男", 25, true, Employee.Type.OFFICER),
new Employee("周七", "男", 29, false, Employee.Type.OFFICER),
new Employee("汪旺", "男", 21, false, Employee.Type.OFFICER),
new Employee("胡涂", "男", 27, false, Employee.Type.OFFICER),
new Employee("杨茂", "男", 34, true, Employee.Type.MANAGER),
new Employee("朱坚", "男", 30, false, Employee.Type.MANAGER)
);
Company<Employee> mouxin = new Company<Employee>("某东", Company.Type.BIG, employees);

employees = Arrays.asList(
new Employee("冯过", "男", 35, false, Employee.Type.SELLER),
new Employee("何花", "女", 27, false, Employee.Type.MANAGER),
new Employee("卫精", "男", 25, true, Employee.Type.OFFICER),
new Employee("施工", "男", 28, false, Employee.Type.OFFICER),
new Employee("沈月", "女", 24, false, Employee.Type.OFFICER),
new Employee("乐欢", "女", 22, false, Employee.Type.OFFICER),
new Employee("安全", "男", 33, true, Employee.Type.MANAGER),
new Employee("林森", "男", 26, true, Employee.Type.SELLER)
);
Company<Employee> wahaha = new Company<Employee>("某哈哈", Company.Type.SMALL, employees);
// 加入列表
list.add(moubao);
list.add(mouxin);
list.add(wahaha);
}


那么,当要实现某宝、某东和某哈哈的员工联谊并解决单身问题时,就会比较麻烦,就像这样:

/**
* 方式一:公司联谊未婚员工登记表:传统方法
*/
List<Employee> unMarriedList1 = new ArrayList<>();
for (Company<Employee> company : list) {
if (company.getType() == Company.Type.BIG) {
List<Employee> emps = company.getEmployees();
// 如果不用Lambda,则必须再次调用排序算法
for (Employee tempEmployee : emps) {
if (!tempEmployee.isMarried()) {
unMarriedList1.add(tempEmployee);
}
}
}
}
// 不用Lambda做排序会非常麻烦
System.out.println("unMarriedList1 -> " + unMarriedList1);


这种方式就完全是一种面向过程的编程,号称纯面向对象设计、编程的Java,在解决这种问题时就是一个讽刺!


既然有了问题,肯定要正视并解决,但解决的方法不在于怎么改进这种代码(大师们的思路往往清奇,但管用)。

在Java还在使用Swing做一些小组件的时候(Swing虽然已经完全被主流应用淘汰了,但代码还保留在Java中),大师们就注意到了一个现象:

Java函数式编程(1):Lambda表达式(1)


可以看到,红色部分的代码几乎没有差别,除了一点内容之外,代码几乎99%都是一样的。而且,类似于

Java函数式编程(1):Lambda表达式(1)


这种代码块,在Java中随处可见。而这种代码块,本质上是由actionListener变量「保存」的。所以,这一过程类就似于「将代码赋值给变量」。

再于是,「优化」过程开始了:

Java函数式编程(1):Lambda表达式(1)


1、因为ActionListener是以匿名类的方式实现的,既然它都已经不想让人知道自己干了什么,退出江湖了,又何必再露脸呢?

2、因为button的addActionListener里面已经要求了ActionListener作为参数,所以其实只要是个稍微聪明点的编译器,它自己就应该能够推断出来需要什么,不用我再来告诉它一次,有点多此一举了;

3、第三点就是,其实咱们写代码,最终是只需要两个东西的,也就是数据和结果,而且这个类本身也是匿名的,所以它完全可以去掉,去掉以后应该是这样的:

Java函数式编程(1):Lambda表达式(1)


接下来,public是多余的,因为只是作为参数了,有没有public没啥区别,所以去掉;然后void也是多余的,编译器可以推断出来有没有返回值,以及它的返回值是啥;然后方法名actionPerformed也是多余的,因为这段代码已经被赋值给「代码块」了,所以它不需要,也不配拥有自己的名字了,所以结果应该是这样的:

Java函数式编程(1):Lambda表达式(1)


精简成这样了,而且进行到这一步,我想Java8开发组的工程师们已经知道自己在干嘛了。刚开始只是尝试着找到优化的方向,另外说一句,咱们可能用了不到几分钟就做到了这一步,那些工程师们可是呕心沥血了几年才达到了这一步的,所以在这里,我们需要向那些优秀的工程师们致敬,感谢他们为我们这些程序员所做出的付出,为整个Java开发社区和生态所做出的贡献!然后,和返回类型一样,需要什么类型的数据编译器也应该是能够自己推断出来的,所以括号里那个ActionEvent也可以省略了:

Java函数式编程(1):Lambda表达式(1)


而进行到这一步,其实代码已经可以放在一行了,就像这样:

Java函数式编程(1):Lambda表达式(1)


但这样太丑了,我想应该是有些颜值控的工程师最终做了这样的改动:

Java函数式编程(1):Lambda表达式(1)


终于大功告成!所以可以用一张图来回顾一下整个Lambda的诞生过程:

Java函数式编程(1):Lambda表达式(1)


虽然这只是我们现在看到的一小步,但是负责维护Java的工程师们应该是往前走了一大步。这种死磕的精神,才是每个码农、工程师们应该学习的。





感谢您的大驾光临!咨询技术、产品、运营和管理相关问题,请关注后留言。欢迎骚扰,不胜荣幸~