目录
1、回顾匿名内部类早期的使用方式、并对比lambad的实现方式
3、如接口中的抽象方法只有一个参数,那么lambad中的参数列表里的小括号可以不写
4、一个以上参数,有返回值,并且lambad体中包含多条语句
5、若lambad中只有一条语句,那么return和大括号都可以省略
1、调用collections.sort()方法,通过定制排序比较两个employee(先按年龄比,年龄相同按姓名比),使用lambad作为参数传递;
Java8的新特性中,有两个特别出彩的地方,一个是lambad表达式,这是一种新的语法。另外,使用lambad结合(也可以不结合)streamAPI,可以使我们操作数据的时候,就像使用sql操作数据一样便捷!甚至,比使用sql语句还要简单!
第一节:java8新特性简介
一、java8新特性的好处
1、速度更快
Java8对底层的数据结构和垃圾回收机制的底层都做了一定的优化,所以他的运行效率要比java8之前更快!
举个例子:
在java8之前,map集合底层使用的是链表+数组去实现的。
Java8之后将其优化为链表+数组+红黑树结构。这种做法可以避免在极端的碰撞情况下导致的效率低下,当某一个链表长度大于8,并且总容量大于64的时候,链表将会转换为红黑树结构,这种结构,除了添加的时候慢一点,其他的操作效率都很高!
另外,在concurrentHashMap中,将之前的分段锁,使用CAS无锁算法进行了替换,CAS无锁的效率大家都知道要比分段锁高很多!
再比如,java8对底层的内存结构也做了一定的调整。他将原来的永久区替换成了元空间,即metaSpace。他使用的是物理内存,而不是分配的内存,这个好处是非常棒的,你物理空间多大,我元空间就可以是多大,他争夺占用的是机器的底层物理资源!
如此一来,垃圾回收机制运行的次数便减少了,也就相应的提高了一定的效率!这里要提出一点,就是这种方式下OOM的发生概率便也随之的大大降低了!
2、代码更少
新增的语法lambad表达式使代码更加的简洁!大大的提高了代码的可读性!
3、强大的streamAPI
这个地方是比较出彩的一个点,他大大的简化了java对数据的操作,使得java在操作数据的时候,可以像sql一样简洁!
4、便于并行
Java8对于并行运行做了一定的优化和支持!
5、最大化的减少空指针异常optional
Java8中提供了一个容器类optional,该类中提供了一系列对空指针的操作,大大的简少了空指针的异常!
第二节:lambad表达式
一、lambad表达式的概念
Lambad是一个匿名函数,我们可以把lambad表达式理解为一段可以传递的代码(将代码像数据一样传递)。可以写出更简洁、更灵活的代码。作为一种更紧凑的代码风格,使java语言表达能力得到了提升!
二、为什么使用lambad表达式
我们在这里使用实例演示来说明,为什么要使用lambad表达式!
1、回顾匿名内部类早期的使用方式、并对比lambad的实现方式
其实从上述对比的案例中,可以看出来,lambad已经大大的简化了代码的数量,如果这个还无法打动你,那么我们接着看下面的对比案例;
package 为什么要使用lambad表达式;
import java.util.Comparator;
import java.util.TreeSet;
/**
* 演示为什么要引入lambad表达式1
* @author yangbao
*/
public class LambadImport1 {
/**
* 最早期的匿名内部类使用
*/
public void EarlyUseOfAnonymousInnerClasses() {
//创建一个用于比较数值大小的匿名内部类
Comparator<Integer> com = new Comparator<Integer>() {
@Override
public int compare(Integer o1, Integer o2) {
return Integer.compare(o1, o2);
}
};
//将匿名内部类作为参数进行传递
TreeSet<Integer> ts = new TreeSet<Integer>(com);
/**
* 分析:上述代码,我们其实核心的,最有用的代码,
* 其实就是匿名内部类中的:return Integer.compare(o1, o2);这一句
* 而其他的一些代码,全部都是为这句代码提供支持的,也就是说,真正
* 干活的代码,就那么一句,然后你还要弄些有的没有乱七八糟的代码。
* 那么这个时候,lambad就诞生了,他的诞生,就是为了解决掉这些
* 有的没有乱七八糟的代码!
*/
}
/**
* 使用lambad表达式实现匿名内部类
*/
public void UsingLambadExpressionsToImplementAnonymousInnerClasses() {
Comparator<Integer> com = (x,y)-> Integer.compare(x,y);
//将lambad作为参数进行传递
TreeSet<Integer> ts = new TreeSet<Integer>(com);
}
}
2、结合一个小需求,将传统实现对比lambad表达式实现
我们给出一个小需求:获取当前公司中员工年龄大于35岁的员工信息!
这样的需求在正常工作中是非常常见的,下面我们分别用几种方式对其进行实现,来一一与lambad表达式的实现对比:
1)、最传统的实现方式
package 为什么要使用lambad表达式;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import 为什么要使用lambad表达式.entity.Employee;
/**
* 演示为什么要引入lambad表达式2
* 如果演示案例1还不足以说明lambad的好处,
* 那么我们使用案例演示2来尝试说明lambad的好处!
*
* 在这里我们提出一个明确的需求:
* 获取当前公司中员工年龄大于35岁的员工信息!
*
* @author yangbao
*/
public class LambadImport2 {
//创建数据
private static List<Employee> employees = Arrays.asList(
new Employee("张三",18,9999.99),
new Employee("李四",38,5555.55),
new Employee("王五",50,6666.66),
new Employee("赵六",16,3333.33),
new Employee("田七", 8,7777.77)
);
/**
* 获取当前公司中员工年龄大于35岁的员工信息!
* @param employees
* @return
*/
public static List<Employee> filterEmployees(List<Employee> employees){
List<Employee> emps = new ArrayList<Employee>();
for(Employee emp:employees) {
if(emp.getAge()>=35) {
emps.add(emp);
}
}
return emps;
}
public static void main(String[] args) {
List<Employee> filterEmployees = filterEmployees(employees);
for(Employee e:filterEmployees) {
System.out.println(e);
}
}
}
运行效果:
Employee [name=李四, age=38, salary=5555.55]
Employee [name=王五, age=50, salary=6666.66]
2)、新增需求
好了,当我们将上面的第一个需求实现之后,又来了一个新的需求,这是很常见的吧:
获取当前公司中员工工资大于5000的员工信息。
那这个时候,就意味着我们还得写一个方法,于是,这个类就变成了如下的样子:
package 为什么要使用lambad表达式;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import 为什么要使用lambad表达式.entity.Employee;
/**
* 演示为什么要引入lambad表达式2
* 如果演示案例1还不足以说明lambad的好处,
* 那么我们使用案例演示2来尝试说明lambad的好处!
*
* 在这里我们提出一个明确的需求:
* 获取当前公司中员工年龄大于35岁的员工信息!
*
* @author yangbao
*/
public class LambadImport2 {
//创建数据
private static List<Employee> employees = Arrays.asList(
new Employee("张三",18,9999.99),
new Employee("李四",38,5555.55),
new Employee("王五",50,6666.66),
new Employee("赵六",16,3333.33),
new Employee("田七", 8,7777.77)
);
/**
* 获取当前公司中员工年龄大于35岁的员工信息!
* @param employees
* @return
*/
public static List<Employee> filterEmployees(List<Employee> employees){
List<Employee> emps = new ArrayList<Employee>();
for(Employee emp:employees) {
if(emp.getAge()>=35) {
emps.add(emp);
}
}
return emps;
}
/**
* 获取当前公司中员工工资大于5000的员工信息
* @param employees
* @return
*/
public static List<Employee> filterEmployeesSalary(List<Employee> employees){
List<Employee> emps = new ArrayList<Employee>();
for(Employee emp:employees) {
if(emp.getSalary()>=5000) {
emps.add(emp);
}
}
return emps;
}
public static void main(String[] args) {
System.out.println("获取当前公司中员工年龄大于35岁的员工信息:");
List<Employee> filterEmployees = filterEmployees(employees);
for(Employee e:filterEmployees) {
System.out.println(e);
}
System.out.println("获取当前公司中员工工资大于5000的员工信息:");
List<Employee> filterEmployeesSalary = filterEmployeesSalary(employees);
for(Employee e:filterEmployeesSalary) {
System.out.println(e);
}
}
}
运行效果:
获取当前公司中员工年龄大于35岁的员工信息:
Employee [name=李四, age=38, salary=5555.55]
Employee [name=王五, age=50, salary=6666.66]
获取当前公司中员工工资大于5000的员工信息:
Employee [name=张三, age=18, salary=9999.99]
Employee [name=李四, age=38, salary=5555.55]
Employee [name=王五, age=50, salary=6666.66]
Employee [name=田七, age=8, salary=7777.77]
实现出来的运行结果是没有问题的,但是这个代码中存在很多的冗余代码,filterEmployees和filterEmployeesSalary两个方法,其实唯一一点不同的地方就是比较的字段不一样!
其余的代码都一样,那么这个时候我们就不得不考虑对其进行抽取封装了!
我们目前来说,对代码最好的优化方式就是使用相应的设计模式,那么我们就使用设计模式来对其进行一个优化:
3、使用策略设计模式,对上述代码进行优化
1)、创建策略接口
package 为什么要使用lambad表达式.inter;
public interface MyPredicate<T> {
/**
* 比较函数
* @param t
* @return
*/
public boolean compare(T t);
}
2)、创建实现类
package 为什么要使用lambad表达式.inter.impl;
import 为什么要使用lambad表达式.entity.Employee;
import 为什么要使用lambad表达式.inter.MyPredicate;
public class FilterEmployeeByAge implements MyPredicate<Employee> {
/**
* 实现比较函数
*/
@Override
public boolean compare(Employee t) {
return t.getAge()>=35;
}
}
package 为什么要使用lambad表达式.inter.impl;
import 为什么要使用lambad表达式.entity.Employee;
import 为什么要使用lambad表达式.inter.MyPredicate;
public class FilterEmployeeBySalary implements MyPredicate<Employee> {
/**
* 实现比较函数
*/
@Override
public boolean compare(Employee t) {
return t.getSalary()>=5000;
}
}
3)、根据不同的策略选择不同的策略接口实现类作为参数
package 为什么要使用lambad表达式;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import 为什么要使用lambad表达式.entity.Employee;
import 为什么要使用lambad表达式.inter.MyPredicate;
import 为什么要使用lambad表达式.inter.impl.FilterEmployeeByAge;
import 为什么要使用lambad表达式.inter.impl.FilterEmployeeBySalary;
/**
* 演示为什么要引入lambad表达式2
* 如果演示案例1还不足以说明lambad的好处,
* 那么我们使用案例演示2来尝试说明lambad的好处!
*
* 在这里我们提出一个明确的需求:
* 获取当前公司中员工年龄大于35岁的员工信息!
*
* @author yangbao
*/
public class LambadImport2 {
//创建数据
private static List<Employee> employees = Arrays.asList(
new Employee("张三",18,9999.99),
new Employee("李四",38,5555.55),
new Employee("王五",50,6666.66),
new Employee("赵六",16,3333.33),
new Employee("田七", 8,7777.77)
);
/**
* 获取当前公司中员工年龄大于35岁的员工信息!
* @param employees
* @return
*/
public static List<Employee> filterEmployees(List<Employee> employees){
List<Employee> emps = new ArrayList<Employee>();
for(Employee emp:employees) {
if(emp.getAge()>=35) {
emps.add(emp);
}
}
return emps;
}
/**
* 获取当前公司中员工工资大于5000的员工信息
* @param employees
* @return
*/
public static List<Employee> filterEmployeesSalary(List<Employee> employees){
List<Employee> emps = new ArrayList<Employee>();
for(Employee emp:employees) {
if(emp.getSalary()>=5000) {
emps.add(emp);
}
}
return emps;
}
/**
* 优化方式1
* @param employeesList
* @param mp
* @return
*/
public static List<Employee> filterEmployee(List<Employee> employeesList,MyPredicate<Employee> mp){
List<Employee> emps = new ArrayList<Employee>();
for(Employee e:employeesList) {
if(mp.compare(e)) {
emps.add(e);
}
}
return emps;
}
public static void main(String[] args) {
System.out.println("获取当前公司中员工年龄大于35岁的员工信息:");
List<Employee> filterEmployees = filterEmployees(employees);
for(Employee e:filterEmployees) {
System.out.println(e);
}
System.out.println("获取当前公司中员工工资大于5000的员工信息:");
List<Employee> filterEmployeesSalary = filterEmployeesSalary(employees);
for(Employee e:filterEmployeesSalary) {
System.out.println(e);
}
System.out.println("优化方式1:");
System.out.println("获取当前公司中员工年龄大于35岁的员工信息:");
List<Employee> filterEmployeeByAge = filterEmployee(employees,new FilterEmployeeByAge());
for(Employee e:filterEmployeeByAge) {
System.out.println(e);
}
System.out.println("获取当前公司中员工工资大于5000的员工信息:");
List<Employee> filterEmployeeBySalary = filterEmployee(employees,new FilterEmployeeBySalary());
for(Employee e:filterEmployeeBySalary) {
System.out.println(e);
}
}
}
4)、运行效果:
获取当前公司中员工年龄大于35岁的员工信息:
Employee [name=李四, age=38, salary=5555.55]
Employee [name=王五, age=50, salary=6666.66]
获取当前公司中员工工资大于5000的员工信息:
Employee [name=张三, age=18, salary=9999.99]
Employee [name=李四, age=38, salary=5555.55]
Employee [name=王五, age=50, salary=6666.66]
Employee [name=田七, age=8, salary=7777.77]
优化方式1:
获取当前公司中员工年龄大于35岁的员工信息:
Employee [name=李四, age=38, salary=5555.55]
Employee [name=王五, age=50, salary=6666.66]
获取当前公司中员工工资大于5000的员工信息:
Employee [name=张三, age=18, salary=9999.99]
Employee [name=李四, age=38, salary=5555.55]
Employee [name=王五, age=50, salary=6666.66]
Employee [name=田七, age=8, salary=7777.77]
5)、分析上述代码的优缺点
那么这么做的好处是什么呢?我们这里的方法只指向一个,即在实现中,只有一个filterEmployee方法,而具体需要对比哪个字段大的值,只需要传递进来相应的MyPredicate接口参数即可!也即是说,选择相应的MyPredicate接口实现类作为参数就可以控制比较的字段!
如果你想按年龄进行过滤,那就将FilterEmployeeByAge类的实例作为参数传递进来;
如果你想按工资进行过滤,那就将FilterEmployeeBySalary类的实例作为参数传递进来;
这样的话,如果新增一个需求,要求按照其他字段进行过滤的话,那么我们只需要编写一个
MyPredicate接口的实现类,在实现类中进行具体逻辑的实现即可!
这个即使优点,同时也是缺点!因为没增加一个需求,都需要编写一个实现类,其实也是很不友好的!
但是目前来说,这基本上也就是最好的一种优化方式了!
4、使用匿名内部类的方式,对上述代码进行优化
1)、代码实现(接口不变)
package 为什么要使用lambad表达式;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import 为什么要使用lambad表达式.entity.Employee;
import 为什么要使用lambad表达式.inter.MyPredicate;
import 为什么要使用lambad表达式.inter.impl.FilterEmployeeByAge;
import 为什么要使用lambad表达式.inter.impl.FilterEmployeeBySalary;
/**
* 演示为什么要引入lambad表达式2
* 如果演示案例1还不足以说明lambad的好处,
* 那么我们使用案例演示2来尝试说明lambad的好处!
*
* 在这里我们提出一个明确的需求:
* 获取当前公司中员工年龄大于35岁的员工信息!
*
* @author yangbao
*/
public class LambadImport2 {
//创建数据
private static List<Employee> employees = Arrays.asList(
new Employee("张三",18,9999.99),
new Employee("李四",38,5555.55),
new Employee("王五",50,6666.66),
new Employee("赵六",16,3333.33),
new Employee("田七", 8,7777.77)
);
/**
* 获取当前公司中员工年龄大于35岁的员工信息!
* @param employees
* @return
*/
public static List<Employee> filterEmployees(List<Employee> employees){
List<Employee> emps = new ArrayList<Employee>();
for(Employee emp:employees) {
if(emp.getAge()>=35) {
emps.add(emp);
}
}
return emps;
}
/**
* 获取当前公司中员工工资大于5000的员工信息
* @param employees
* @return
*/
public static List<Employee> filterEmployeesSalary(List<Employee> employees){
List<Employee> emps = new ArrayList<Employee>();
for(Employee emp:employees) {
if(emp.getSalary()>=5000) {
emps.add(emp);
}
}
return emps;
}
/**
* 优化方式1
* @param employeesList
* @param mp
* @return
*/
public static List<Employee> filterEmployee(List<Employee> employeesList,MyPredicate<Employee> mp){
List<Employee> emps = new ArrayList<Employee>();
for(Employee e:employeesList) {
if(mp.compare(e)) {
emps.add(e);
}
}
return emps;
}
public static void main(String[] args) {
System.out.println("获取当前公司中员工年龄大于35岁的员工信息:");
List<Employee> filterEmployees = filterEmployees(employees);
for(Employee e:filterEmployees) {
System.out.println(e);
}
System.out.println("获取当前公司中员工工资大于5000的员工信息:");
List<Employee> filterEmployeesSalary = filterEmployeesSalary(employees);
for(Employee e:filterEmployeesSalary) {
System.out.println(e);
}
System.out.println("优化方式1,使用策略模式对其进行优化:");
System.out.println("获取当前公司中员工年龄大于35岁的员工信息:");
List<Employee> filterEmployeeByAge = filterEmployee(employees,new FilterEmployeeByAge());
for(Employee e:filterEmployeeByAge) {
System.out.println(e);
}
System.out.println("获取当前公司中员工工资大于5000的员工信息:");
List<Employee> filterEmployeeBySalary = filterEmployee(employees,new FilterEmployeeBySalary());
for(Employee e:filterEmployeeBySalary) {
System.out.println(e);
}
System.out.println("优化方式2,使用匿名内部类的方式,对上述代码进行优化:");
System.out.println("获取当前公司中员工年龄大于35岁的员工信息:");
List<Employee> earlyUseOfAnonymousInnerClassesByAgeList = filterEmployee(employees,new MyPredicate<Employee>() {
@Override
public boolean compare(Employee t) {
return t.getAge()>=35;
}
});
for(Employee e:earlyUseOfAnonymousInnerClassesByAgeList) {
System.out.println(e);
}
System.out.println("获取当前公司中员工工资大于5000的员工信息:");
List<Employee> earlyUseOfAnonymousInnerClassesListBySalaryList = filterEmployee(employees,new MyPredicate<Employee>() {
@Override
public boolean compare(Employee t) {
return t.getSalary()>=5000;
}
});
for(Employee e:earlyUseOfAnonymousInnerClassesListBySalaryList) {
System.out.println(e);
}
}
}
2)、运行效果:
获取当前公司中员工年龄大于35岁的员工信息:
Employee [name=李四, age=38, salary=5555.55]
Employee [name=王五, age=50, salary=6666.66]
获取当前公司中员工工资大于5000的员工信息:
Employee [name=张三, age=18, salary=9999.99]
Employee [name=李四, age=38, salary=5555.55]
Employee [name=王五, age=50, salary=6666.66]
Employee [name=田七, age=8, salary=7777.77]
优化方式1,使用策略模式对其进行优化:
获取当前公司中员工年龄大于35岁的员工信息:
Employee [name=李四, age=38, salary=5555.55]
Employee [name=王五, age=50, salary=6666.66]
获取当前公司中员工工资大于5000的员工信息:
Employee [name=张三, age=18, salary=9999.99]
Employee [name=李四, age=38, salary=5555.55]
Employee [name=王五, age=50, salary=6666.66]
Employee [name=田七, age=8, salary=7777.77]
优化方式2,使用匿名内部类的方式,对上述代码进行优化:
获取当前公司中员工年龄大于35岁的员工信息:
Employee [name=李四, age=38, salary=5555.55]
Employee [name=王五, age=50, salary=6666.66]
获取当前公司中员工工资大于5000的员工信息:
Employee [name=张三, age=18, salary=9999.99]
Employee [name=李四, age=38, salary=5555.55]
Employee [name=王五, age=50, salary=6666.66]
Employee [name=田七, age=8, salary=7777.77]
3)、分析上述代码的优缺点
优点:从上述实现的代码来看,我们不再需要创建实现类了,而是在匿名内部类中对具体的逻辑进行处理!
缺点:我们前面演示过使用匿名内部类来对比lambad表达式,那个时候我们是不是说过,其实这个匿名内部类中,实际上起作用的代码,就是实现方法中的内容,其余的全部没有用,只是一个架子而已!那么这个时候,我们就可以使用lambad表达式来对其进行优化了!
5、使用lambad表达式,对上述代码进行优化
1)、代码实现
package 为什么要使用lambad表达式;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import 为什么要使用lambad表达式.entity.Employee;
import 为什么要使用lambad表达式.inter.MyPredicate;
import 为什么要使用lambad表达式.inter.impl.FilterEmployeeByAge;
import 为什么要使用lambad表达式.inter.impl.FilterEmployeeBySalary;
/**
* 演示为什么要引入lambad表达式2
* 如果演示案例1还不足以说明lambad的好处,
* 那么我们使用案例演示2来尝试说明lambad的好处!
*
* 在这里我们提出一个明确的需求:
* 获取当前公司中员工年龄大于35岁的员工信息!
*
* @author yangbao
*/
public class LambadImport2 {
//创建数据
private static List<Employee> employees = Arrays.asList(
new Employee("张三",18,9999.99),
new Employee("李四",38,5555.55),
new Employee("王五",50,6666.66),
new Employee("赵六",16,3333.33),
new Employee("田七", 8,7777.77)
);
/**
* 获取当前公司中员工年龄大于35岁的员工信息!
* @param employees
* @return
*/
public static List<Employee> filterEmployees(List<Employee> employees){
List<Employee> emps = new ArrayList<Employee>();
for(Employee emp:employees) {
if(emp.getAge()>=35) {
emps.add(emp);
}
}
return emps;
}
/**
* 获取当前公司中员工工资大于5000的员工信息
* @param employees
* @return
*/
public static List<Employee> filterEmployeesSalary(List<Employee> employees){
List<Employee> emps = new ArrayList<Employee>();
for(Employee emp:employees) {
if(emp.getSalary()>=5000) {
emps.add(emp);
}
}
return emps;
}
/**
* 优化方式1
* @param employeesList
* @param mp
* @return
*/
public static List<Employee> filterEmployee(List<Employee> employeesList,MyPredicate<Employee> mp){
List<Employee> emps = new ArrayList<Employee>();
for(Employee e:employeesList) {
if(mp.compare(e)) {
emps.add(e);
}
}
return emps;
}
public static void main(String[] args) {
System.out.println("获取当前公司中员工年龄大于35岁的员工信息:");
List<Employee> filterEmployees = filterEmployees(employees);
for(Employee e:filterEmployees) {
System.out.println(e);
}
System.out.println("获取当前公司中员工工资大于5000的员工信息:");
List<Employee> filterEmployeesSalary = filterEmployeesSalary(employees);
for(Employee e:filterEmployeesSalary) {
System.out.println(e);
}
System.out.println("优化方式1,使用策略模式对其进行优化:");
System.out.println("获取当前公司中员工年龄大于35岁的员工信息:");
List<Employee> filterEmployeeByAge = filterEmployee(employees,new FilterEmployeeByAge());
for(Employee e:filterEmployeeByAge) {
System.out.println(e);
}
System.out.println("获取当前公司中员工工资大于5000的员工信息:");
List<Employee> filterEmployeeBySalary = filterEmployee(employees,new FilterEmployeeBySalary());
for(Employee e:filterEmployeeBySalary) {
System.out.println(e);
}
System.out.println("优化方式2,使用匿名内部类的方式,对上述代码进行优化:");
System.out.println("获取当前公司中员工年龄大于35岁的员工信息:");
List<Employee> earlyUseOfAnonymousInnerClassesByAgeList = filterEmployee(employees,new MyPredicate<Employee>() {
@Override
public boolean compare(Employee t) {
return t.getAge()>=35;
}
});
for(Employee e:earlyUseOfAnonymousInnerClassesByAgeList) {
System.out.println(e);
}
System.out.println("获取当前公司中员工工资大于5000的员工信息:");
List<Employee> earlyUseOfAnonymousInnerClassesListBySalaryList = filterEmployee(employees,new MyPredicate<Employee>() {
@Override
public boolean compare(Employee t) {
return t.getSalary()>=5000;
}
});
for(Employee e:earlyUseOfAnonymousInnerClassesListBySalaryList) {
System.out.println(e);
}
System.out.println("优化方式3,使用lambad表达式,对上述代码进行优化:");
System.out.println("获取当前公司中员工年龄大于35岁的员工信息:");
List<Employee> lambadByAgeList = filterEmployee(employees,(e)->e.getAge()>=35);
lambadByAgeList.forEach(System.out::println);
System.out.println("获取当前公司中员工工资大于5000的员工信息:");
List<Employee> lambadBySalaryList = filterEmployee(employees,(e)->e.getSalary()>=5000);
lambadBySalaryList.forEach(System.out::println);
}
}
2)、运行效果
获取当前公司中员工年龄大于35岁的员工信息:
Employee [name=李四, age=38, salary=5555.55]
Employee [name=王五, age=50, salary=6666.66]
获取当前公司中员工工资大于5000的员工信息:
Employee [name=张三, age=18, salary=9999.99]
Employee [name=李四, age=38, salary=5555.55]
Employee [name=王五, age=50, salary=6666.66]
Employee [name=田七, age=8, salary=7777.77]
优化方式1,使用策略模式对其进行优化:
获取当前公司中员工年龄大于35岁的员工信息:
Employee [name=李四, age=38, salary=5555.55]
Employee [name=王五, age=50, salary=6666.66]
获取当前公司中员工工资大于5000的员工信息:
Employee [name=张三, age=18, salary=9999.99]
Employee [name=李四, age=38, salary=5555.55]
Employee [name=王五, age=50, salary=6666.66]
Employee [name=田七, age=8, salary=7777.77]
优化方式2,使用匿名内部类的方式,对上述代码进行优化:
获取当前公司中员工年龄大于35岁的员工信息:
Employee [name=李四, age=38, salary=5555.55]
Employee [name=王五, age=50, salary=6666.66]
获取当前公司中员工工资大于5000的员工信息:
Employee [name=张三, age=18, salary=9999.99]
Employee [name=李四, age=38, salary=5555.55]
Employee [name=王五, age=50, salary=6666.66]
Employee [name=田七, age=8, salary=7777.77]
优化方式3,使用lambad表达式,对上述代码进行优化:
获取当前公司中员工年龄大于35岁的员工信息:
Employee [name=李四, age=38, salary=5555.55]
Employee [name=王五, age=50, salary=6666.66]
获取当前公司中员工工资大于5000的员工信息:
Employee [name=张三, age=18, salary=9999.99]
Employee [name=李四, age=38, salary=5555.55]
Employee [name=王五, age=50, salary=6666.66]
Employee [name=田七, age=8, salary=7777.77]
3)、分析上述代码的优缺点
优点:上述代码,基本上已经将策略模式精简到了极致了,但是,优点就不言而喻了吧!
缺点:还是有人会不满意,那么没关系,我们再往下看!
6、使用stream,对上述代码进行优化
1)、代码实现
package 为什么要使用lambad表达式;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import 为什么要使用lambad表达式.entity.Employee;
import 为什么要使用lambad表达式.inter.MyPredicate;
import 为什么要使用lambad表达式.inter.impl.FilterEmployeeByAge;
import 为什么要使用lambad表达式.inter.impl.FilterEmployeeBySalary;
/**
* 演示为什么要引入lambad表达式2
* 如果演示案例1还不足以说明lambad的好处,
* 那么我们使用案例演示2来尝试说明lambad的好处!
*
* 在这里我们提出一个明确的需求:
* 获取当前公司中员工年龄大于35岁的员工信息!
*
* @author yangbao
*/
public class LambadImport2 {
//创建数据
private static List<Employee> employees = Arrays.asList(
new Employee("张三",18,9999.99),
new Employee("李四",38,5555.55),
new Employee("王五",50,6666.66),
new Employee("赵六",16,3333.33),
new Employee("田七", 8,7777.77)
);
/**
* 获取当前公司中员工年龄大于35岁的员工信息!
* @param employees
* @return
*/
public static List<Employee> filterEmployees(List<Employee> employees){
List<Employee> emps = new ArrayList<Employee>();
for(Employee emp:employees) {
if(emp.getAge()>=35) {
emps.add(emp);
}
}
return emps;
}
/**
* 获取当前公司中员工工资大于5000的员工信息
* @param employees
* @return
*/
public static List<Employee> filterEmployeesSalary(List<Employee> employees){
List<Employee> emps = new ArrayList<Employee>();
for(Employee emp:employees) {
if(emp.getSalary()>=5000) {
emps.add(emp);
}
}
return emps;
}
/**
* 优化方式1
* @param employeesList
* @param mp
* @return
*/
public static List<Employee> filterEmployee(List<Employee> employeesList,MyPredicate<Employee> mp){
List<Employee> emps = new ArrayList<Employee>();
for(Employee e:employeesList) {
if(mp.compare(e)) {
emps.add(e);
}
}
return emps;
}
public static void main(String[] args) {
System.out.println("获取当前公司中员工年龄大于35岁的员工信息:");
List<Employee> filterEmployees = filterEmployees(employees);
for(Employee e:filterEmployees) {
System.out.println(e);
}
System.out.println("获取当前公司中员工工资大于5000的员工信息:");
List<Employee> filterEmployeesSalary = filterEmployeesSalary(employees);
for(Employee e:filterEmployeesSalary) {
System.out.println(e);
}
System.out.println("优化方式1,使用策略模式对其进行优化:");
System.out.println("获取当前公司中员工年龄大于35岁的员工信息:");
List<Employee> filterEmployeeByAge = filterEmployee(employees,new FilterEmployeeByAge());
for(Employee e:filterEmployeeByAge) {
System.out.println(e);
}
System.out.println("获取当前公司中员工工资大于5000的员工信息:");
List<Employee> filterEmployeeBySalary = filterEmployee(employees,new FilterEmployeeBySalary());
for(Employee e:filterEmployeeBySalary) {
System.out.println(e);
}
System.out.println("优化方式2,使用匿名内部类的方式,对上述代码进行优化:");
System.out.println("获取当前公司中员工年龄大于35岁的员工信息:");
List<Employee> earlyUseOfAnonymousInnerClassesByAgeList = filterEmployee(employees,new MyPredicate<Employee>() {
@Override
public boolean compare(Employee t) {
return t.getAge()>=35;
}
});
for(Employee e:earlyUseOfAnonymousInnerClassesByAgeList) {
System.out.println(e);
}
System.out.println("获取当前公司中员工工资大于5000的员工信息:");
List<Employee> earlyUseOfAnonymousInnerClassesListBySalaryList = filterEmployee(employees,new MyPredicate<Employee>() {
@Override
public boolean compare(Employee t) {
return t.getSalary()>=5000;
}
});
for(Employee e:earlyUseOfAnonymousInnerClassesListBySalaryList) {
System.out.println(e);
}
System.out.println("优化方式3,使用lambad表达式,对上述代码进行优化:");
System.out.println("获取当前公司中员工年龄大于35岁的员工信息:");
List<Employee> lambadByAgeList = filterEmployee(employees,(e)->e.getAge()>=35);
lambadByAgeList.forEach(System.out::println);
System.out.println("获取当前公司中员工工资大于5000的员工信息:");
List<Employee> lambadBySalaryList = filterEmployee(employees,(e)->e.getSalary()>=5000);
lambadBySalaryList.forEach(System.out::println);
System.out.println("优化方式4,使用stream语法,对上述代码进行优化:");
System.out.println("获取当前公司中员工年龄大于35岁的员工信息:");
employees.stream().filter((e)->e.getAge()>=35).forEach(System.out::println);
System.out.println("获取当前公司中员工工资大于5000的员工信息:");
employees.stream().filter((e)->e.getSalary()>=5000).forEach(System.out::println);
}
}
2)、运行效果
获取当前公司中员工年龄大于35岁的员工信息:
Employee [name=李四, age=38, salary=5555.55]
Employee [name=王五, age=50, salary=6666.66]
获取当前公司中员工工资大于5000的员工信息:
Employee [name=张三, age=18, salary=9999.99]
Employee [name=李四, age=38, salary=5555.55]
Employee [name=王五, age=50, salary=6666.66]
Employee [name=田七, age=8, salary=7777.77]
优化方式1,使用策略模式对其进行优化:
获取当前公司中员工年龄大于35岁的员工信息:
Employee [name=李四, age=38, salary=5555.55]
Employee [name=王五, age=50, salary=6666.66]
获取当前公司中员工工资大于5000的员工信息:
Employee [name=张三, age=18, salary=9999.99]
Employee [name=李四, age=38, salary=5555.55]
Employee [name=王五, age=50, salary=6666.66]
Employee [name=田七, age=8, salary=7777.77]
优化方式2,使用匿名内部类的方式,对上述代码进行优化:
获取当前公司中员工年龄大于35岁的员工信息:
Employee [name=李四, age=38, salary=5555.55]
Employee [name=王五, age=50, salary=6666.66]
获取当前公司中员工工资大于5000的员工信息:
Employee [name=张三, age=18, salary=9999.99]
Employee [name=李四, age=38, salary=5555.55]
Employee [name=王五, age=50, salary=6666.66]
Employee [name=田七, age=8, salary=7777.77]
优化方式3,使用lambad表达式,对上述代码进行优化:
获取当前公司中员工年龄大于35岁的员工信息:
Employee [name=李四, age=38, salary=5555.55]
Employee [name=王五, age=50, salary=6666.66]
获取当前公司中员工工资大于5000的员工信息:
Employee [name=张三, age=18, salary=9999.99]
Employee [name=李四, age=38, salary=5555.55]
Employee [name=王五, age=50, salary=6666.66]
Employee [name=田七, age=8, salary=7777.77]
优化方式4,使用stream语法,对上述代码进行优化:
获取当前公司中员工年龄大于35岁的员工信息:
Employee [name=李四, age=38, salary=5555.55]
Employee [name=王五, age=50, salary=6666.66]
获取当前公司中员工工资大于5000的员工信息:
Employee [name=张三, age=18, salary=9999.99]
Employee [name=李四, age=38, salary=5555.55]
Employee [name=王五, age=50, salary=6666.66]
Employee [name=田七, age=8, salary=7777.77]
3)、分析上述代码的优缺点
优点:代码及其简洁
缺点:需要学习
三、lambad表达式基础语法
1、lambad基础语法概述
Java8中引入了一个新的操作符“->”,该操作符称为箭头操作符或者lambad操作符,箭头操作符将整个lambad表达式拆分成了两个部分,分别是箭头左侧的部分和箭头右侧的部分:
1)、箭头左侧的部分
左侧部分为lambad表达式的参数列表!
2)、箭头右侧的部分
右侧部分为lambad体,该部分为lambad具体要执行的逻辑代码!
我们通过上述的演示案例和语法概念,可以总结出来,所谓的lambad表达式,就是一种对接口的实现的简易写法!
public interface MyPredicate<T>{
//比较函数
Public Boolean compare(T t);
}
如上图所示,我们lambad左侧的参数列表,指的就是这个接口中方法的参数列表,要求与之一一对应;而右侧的lambad体,指的就是实现类中该方法的实现中的逻辑代码,见下图中代码的蓝色部分:
package 为什么要使用lambad表达式.inter.impl;
import 为什么要使用lambad表达式.entity.Employee; import 为什么要使用lambad表达式.inter.MyPredicate;
public class FilterEmployeeByAge implements MyPredicate<Employee> {
/** * 实现比较函数 */ @Override public boolean compare(Employee t) { return t.getAge()>=35; } } |
最后,我们结合语法和业务逻辑,便可实现一个lambad表达式:
List<Employee> lambadByAgeList = filterEmployee(employees,(e)->e.getAge()>=35); |
那么这个时候我们就会有一个疑问,既然lambad表达式要对接口中的抽象方法做实现,那么他具体要实现哪个抽象方法呢?
这个问题,就需要一个函数式接口来对其进行支持,那么什么是函数式接口呢?就是一个接口中,只有一个抽象方法!这个我们后面再说,这里先记一下这个点!
我们先简单的了解lambad语法的几种变换格式;
四、lambad语法的几种格式
这里再次强调一点,lambad表达式是对接口中的抽象类做具体实现的!
而我们接口中的抽象类,有很多种形式,有无惨的,有有参数的,有多参数的,有带返回值的,有不带返回值的,等等!
我们来了解一下lambad表达式对这几种抽象类的实现时什么样子的!
1、无参无返回值
我们知道Runnable接口就符合这样的条件,我们以Runnable接口为例来进行演示:
1)、代码实现:
package lambad表达式基础语法;
public class TestLambad1 {
public static void main(String[] args) { System.out.println("调用原始实现方式"); originalImplementation(); System.out.println("调用lambad实现方式"); lambadlImplementation(); }
/** * 原始实现方式 */ public static void originalImplementation() { Runnable r = new Runnable() { @Override public void run() { System.out.println("hello world");
} }; r.run(); }
/** * lambad实现方式 */ public static void lambadlImplementation() { Runnable r = ()->System.out.println("hello lambad"); r.run(); } } |
2)、运行效果:
调用原始实现方式 hello world 调用lambad实现方式 hello lambad |
3)、总结:
Runnable r = () -> System.out.println("hello lambad");
红色部分为方法的返回值;
蓝色部分为接口中的抽象方法的参数列表;
绿色部分为lambad符号;
褐色部分为接口中的抽象方法的实现逻辑代码;
4)、注意事项
在局部内部类中使用到了同级别的局部变量的时候:
在jdk1.8以前,这个变量必须显式的声明为final类型的,但是在jdk1.8以后,无需显式的将其声明为final类型的,但是他本质上还是一个final类型的,他的值,不可以改变!
正确用法:
public static void originalImplementation() { int num = 0; Runnable r = new Runnable() { @Override public void run() { System.out.println("hello world"+num);
} }; r.run(); } |
错误用法:
public static void originalImplementation() { int num = 0; Runnable r = new Runnable() { @Override public void run() { System.out.println("hello world"+num++);
} }; r.run(); } |
同样的,lambad也需要遵循这样的原则:
正确使用:
public static void lambadlImplementation() { int num = 0; Runnable r = ()->System.out.println("hello lambad"+num); r.run(); } |
错误使用:
public static void lambadlImplementation() { int num = 0; Runnable r = ()->System.out.println("hello lambad"+num++); r.run(); } |
2、有一个参数,并且无返回值
1)、代码实现
package lambad表达式基础语法; import java.util.function.Consumer; public class TestLambad1 { public static void main(String[] args) { lambadlImplementation2(); } public static void lambadlImplementation2() { Consumer<String> con = (x)->System.out.println(x); con.accept("你好杨保"); } } |
2)、运行效果
你好杨保 |
3)、总结
Consumer<String> con = (x)->System.out.println(x);
红色部分:方法的返回值;
蓝色部分:参数列表,其中x可以为任何字符串;
绿色部分:lambad符号;
褐色部分:方法的实现逻辑代码;
3、如接口中的抽象方法只有一个参数,那么lambad中的参数列表里的小括号可以不写
1)、代码实现
package lambad表达式基础语法; import java.util.function.Consumer; public class TestLambad1 { public static void main(String[] args) { lambadlImplementation3(); } public static void lambadlImplementation3() { Consumer<String> con = x->System.out.println(x); con.accept("你好杨保"); } } |
2)、运行效果
你好杨保 |
3)、总结
Consumer<String> con = x->System.out.println(x);
红色部分:方法的返回值;
蓝色部分:参数列表,其中x可以为任何字符串;如果方法的参数只有一个,小括号可以忽略不写;
绿色部分:lambad符号;
褐色部分:方法的实现逻辑代码;
4、一个以上参数,有返回值,并且lambad体中包含多条语句
1)、代码实现
package lambad表达式基础语法; import java.util.Comparator; import java.util.function.Consumer; public class TestLambad1 { public static void main(String[] args) { lambadlImplementation4(); } public static void lambadlImplementation4() { Comparator<Integer> com = (x,y)->{ System.out.println("函数式接口"); return Integer.compare(x, y); }; int res = com.compare(1,2); System.out.println(res); } } |
2)、运行效果
函数式接口 -1 |
3)、总结
Comparator<Integer> com = (x,y)->{
System.out.println("函数式接口");
return Integer.compare(x, y);
};
红色部分:接口的实例对象;
蓝色部分:接口中抽象方法的参数列表,其中x,y类似于占位符,写什么字符串放在这里都可以;
绿色部分:lambad符号;
褐色部分:接口中抽象方法的实现逻辑代码,如果该实现逻辑需要多行代码,那么必须使用大括号对其进行包裹!
5、若lambad中只有一条语句,那么return和大括号都可以省略
1)、代码实现
package lambad表达式基础语法; import java.util.Comparator; import java.util.function.Consumer; public class TestLambad1 { public static void main(String[] args) { lambadlImplementation5(); }
public static void lambadlImplementation5() { Comparator<Integer> com = (x,y)->Integer.compare(x, y); int res = com.compare(1,2); System.out.println(res); } } |
2)、运行效果
-1 |
3)、总结
Comparator<Integer> com = (x,y)->Integer.compare(x, y);
红色部分:接口的实例对象;
蓝色部分:接口中抽象方法的参数列表,如果只有一个参数的话,小括号可以省略;
绿色部分:lambad符号;
褐色部分:接口中抽象方法的实现逻辑代码,如果该方法需要返回值,并且lambad中只有一句代码,那么return可以省略不写,同时{}大括号也可以省略不写;
6、参数推导
Lambad表达式的参数列表的数据类型可以省略不写,因为JVM编译器可以通过上下文推断出数据类型,即:参数推断;
1)、代码实现
package lambad表达式基础语法;
import java.util.Comparator; import java.util.function.Consumer;
public class TestLambad1 {
public static void main(String[] args) { lambadlImplementation6(); } public static void lambadlImplementation6() { Comparator<Integer> com = (Integer x,Integer y)->Integer.compare(x, y); int res = com.compare(1,2); System.out.println(res); } } |
2)、运行效果
-1 |
3)、总结
Comparator<Integer> com = (Integer x,Integer y)->Integer.compare(x, y);
红色部分:方法的返回值;
蓝色部分:参数列表,其中x可以为任何字符串;如果方法的参数只有一个,小括号可以忽略不写;这里是写全了的样子,是可以加上参数类型的;
绿色部分:lambad符号;
褐色部分:方法的实现逻辑代码;
五、lambad表达式与接口关系
1、函数式接口的支持
我们前面说过,lambad是对接口中的方法进行实现,并且接口中的方法还不能多,多了就区分不了了,那么针对这个地方,我们给与解释说明;
首先,lambad需要函数式接口的支持,那么什么是函数式接口呢?
若接口中只有一个抽象方法的接口,那么我们就称其为函数式接口;
我们可以使用注解@FunctionalInterface标注某个接口为函数式接口;
使用该注解之后,可以对该接口进行检查,检查其是否为函数式接口;
其实,这就是lambad的限制条件;
备足:lambad+策略模式,是一种非常友好的实现之一;
六、lambad表达式小练习
1、调用collections.sort()方法,通过定制排序比较两个employee(先按年龄比,年龄相同按姓名比),使用lambad作为参数传递;
1)、代码实现
package 联系题;
import java.util.Arrays; import java.util.Collections; import java.util.List; import 为什么要使用lambad表达式.entity.Employee;
public class TestLambad {
//创建数据 private static List<Employee> employeesList = Arrays.asList( new Employee("张三",18,9999.99), new Employee("李四",38,5555.55), new Employee("王五",50,6666.66), new Employee("赵六",16,3333.33), new Employee("田七", 8,7777.77) );
public static void test1() { Collections.sort(employeesList, (e1,e2)->{ if(e1.getAge()==e2.getAge()) { return e1.getName().compareTo(e2.getName()); }else { return Integer.compare(e1.getAge(),e2.getAge()); } }); }
public static void main(String[] args) { test1(); employeesList.forEach(e->System.out.println(e)); } } |
2)、运行效果:
Employee [name=田七, age=8, salary=7777.77] Employee [name=赵六, age=16, salary=3333.33] Employee [name=张三, age=18, salary=9999.99] Employee [name=李四, age=38, salary=5555.55] Employee [name=王五, age=50, salary=6666.66] |
2、自定义练习题1
声明一个带有两个泛型的函数式接口,泛型为<T,R>,T为参数,R为返回值;
接口中声明抽象方法;
在TestLambad类中声明方法,使用接口作为参数,计算两个long类型参数的和;
再计算两个long类型参数的积;
1)、代码实现
package 联系题;
import java.util.Arrays; import java.util.Collections; import java.util.List; import 为什么要使用lambad表达式.entity.Employee; import 联系题.inter.MyFun; import 联系题.inter.MyFunction;
public class TestLambad { public static void test3() { Long longHadnler1 = longHadnler(100l,200l,(l1,l2)->l1+l2); System.out.println(longHadnler1); Long longHadnler2 = longHadnler(100l,200l,(l1,l2)->l1*l2); System.out.println(longHadnler2); }
/** * 对两个泛型数据进行处理 * @param str * @param mf * @return */ public static Long longHadnler(Long l1,Long l2,MyFun<Long,Long> mf) { return mf.getValue(l1,l2); }
public static void main(String[] args) { test3(); } } |
2)、运行效果
300 20000 |