一. 前言部分
大家都知道Lambda表达式作为JAVA 8中提供的新特性之一,在现在的企业开发中已经非常的流行了。今天壹哥就通过一个具体的案例,来带大家一起详细地探究一下Lambda表达式是如何被提出来的,以及它的出现主要是用来解决什么问题的。相信通过本文内容的讲解,各位小伙伴一定会对Lambda有一个更深入全面的认识,让我们一起开始吧。
二. 案例说明
1. 定义一个学生类
我们先来定义一个学生类。
package com.qf.day12.demo02;
public class Student {
private String sno;
private String name;
private int age;
private double score;
public String getSno() {
return sno;
}
public void setSno(String sno) {
this.sno = sno;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public double getScore() {
return score;
}
public void setScore(double score) {
this.score = score;
}
public Student(String sno, String name, int age, double score) {
super();
this.sno = sno;
this.name = name;
this.age = age;
this.score = score;
}
public Student() {
super();
}
public void showInfo() {
System.out.println("学号:"+ this.sno +",姓名:" + this.name + ",年龄:" + age + ",成绩:"+ this.score);
}
}
2. 创建学生数组
在main方法中创建一个学生对象数组。
public static void main(String[] args) {
//创建一个学生对象数组
Student[] students = new Student[] {
new Student("101","张三",23,89.5),
new Student("102","李四",28,79.5),
new Student("103","王五",20,90.5),
new Student("104","赵六",26,34.5),
new Student("105","田七",19,67.5),
new Student("106","孙八",22,56.5)
};
}
下面我们来看一个需求:定义一个方法,能够根据用户提供的不同条件从整个数组中进行指学生信息的检索并输出检索的结果,这其实就是开发中非常普遍的信息查询功能。
三. 解决过程
了解到上述需求后,下面我们再来看壹哥对这个检索方法的设计。
1. 定义接口
首先我们来定义一个接口,并在接口中定义一个能够对学生对象按照一定条件进行判断的抽象方法,具体的判断规则和逻辑交由实现类去实现:
public interface Judgeable {
//制定统一的判断方法规范
boolean judge(Student s);
}
2. 编写实现类
接着编写接口的第一个实现类,具体的实现逻辑是判断学生成绩是否及格:
public class JudgeByScore implements Judgeable{
@Override
public boolean judge(Student s) {
if(s.getScore()>=60) {
return true;
}
return false;
}
}
3. 实现信息检索
定义按给定条件进行学生信息检索的方法:
public static void filter(Student[] students,Judgeable judgeable) {
for (int i = 0; i < students.length; i++) {
if(judgeable.judge(students[i])) {
students[i].showInfo();
}
}
}
4. 进行信息过滤
在main方法中调用filter方法进行及格的学生信息过滤:
filter(students, new JudgeByScore());
虽然需求是得到了解决,但我们也不难发现这种方式存在的问题:JudgeByScore这个类只能按照成绩进行过滤,那如果我们希望按照年龄进行过滤呢?这时我们又得编写一个接口的实现类,这样随着筛选条件的不断增多例如按照学号过滤、按照姓名过滤、过滤出90分以上的等等,我们就需要在项目中不断的编写实现类,这样就造成了类的泛滥,这又该如何解决呢?
此时我们可以想到使用JAVA中的匿名内部类对象语法进行上述过程的优化,具体的代码如下:
filter(students, new Judgeable() {
@Override
public boolean judge(Student s) {
return s.getScore()>=60;
}
});
匿名内部类属于局部内部类的一种特殊情况,它其实就是将某个接口的实现类的定义和该实现类对象的创建合二为一,同时在这个过程中隐藏了实现类的名字。这样做的好处无疑是简化了我们的编码,在项目的目录中也没有产生新的类文件从而解决了类的泛滥问题。估计到这里,小伙伴们都没有什么问题。但是上述代码还能不能继续简化呢?答案是肯定的,我们今天的探讨的主角Lambda表达式正式登场...
5. Lambda简化操作
小伙伴们会发现上面的filter过滤方法调用的第二个参数过于繁琐,整个匿名内部类对象创建过程中很多的部分都是可以结合程序上下文进行推断出来的,并没有必要体现在代码中。例如:new 后面接口类型可以通过filter方法的第二个形参类型来推断,包括实现的方法声明部分public boolean judge(Student s)
按照方法实现的要求必须和接口中定义的规范保持一致,所以这块也可以省略不写,所以我们可以将传递的第二个参数【匿名内部类对象】通过Lambda表达式的语法规则进行进一步的简化:
filter(students,(s)->{ return s.getScore()>=60; } );
以->为分割,左侧表示方法的形参列表,右侧表示方法体或方法的实现,由此我们可以认为Lambda表达式其实就是按照一定的规则对匿名内部类对象的语法简化。它最终描述的是一个实现了指定接口的方法,并且要求Lambda所描述的方法的形参列表以及返回的结果类型必须完全符合接口规范,因此我们在编写Lambda表达式的过程中脑子里想的是对应接口中方法规范。这时可能会有小伙伴问:如果接口中定义了多个抽象方法呢,我们在基于这样的接口编写Lambda表达式到底参考哪个呢?
注意了:Lambda表达式的编写是有条件的,并不是任何接口的匿名内部类对象都可以使用Lambda来简化,我们要求这个接口中只能定义一个必须被实现类强制实现的方法。也就是我们JAVA中所说的函数式接口,可以通过专门的注解@FunctionalInterface进行是否为函数式接口的标识。
根据Lambda的规则要求:
1. 如果形参只有一个的话参数的小括号可以省略不写;
2. 如果Lambda体中只要一条return语句则return关键字、Lambda的大括号以及语句的结束符分号均可同时省略。
我们还可以对上面的调用过程做进一步的简化,让整个代码看起来更加的紧凑:
filter(students,s->s.getScore()>=60);
感觉这就像是将一段代码作为方法的参数进行传递一样。
四. 内容总结
以上就是如何通过Lambda表达式,一步步精简匿名内部类对象的完整过程。正如有的小伙伴所理解的,因为JAVA 8之前对匿名内部类对象的编写语法太繁琐,所以才有了JAVA 8之后提出的Lambda表达式,用来进行语法简化提升开发效率的。通过近期毕业的学员反馈回来的信息,Lambda表达式目前在企业开发中已经非常流行了。作为个人。你可以选择不去使用它,但是作为一个团队大家都在使用的话,你作为团队的一份子如果不会,是不是很难和团队成员进行配合,是不是很容易被其他人认为你已经OUT了呢?