之前因为公司服务器一直使用jdk1.7环境所以java8的很多新特性都不能在项目中使用,前几个月于是就把公司java环境进行升级处理,然后在项目中开始使用java8新语法特性。之前自己的开源项目就一直使用jdk1.8所以对新特性不能用在公司项目中很烦,造成出现大部分垃圾代码,趁着此次机会对Lambda表达式进行总结。
为什么要用Lambada表达式
Lambda表达式说白了就是一个匿名函数,可以更加简单明了的表达想要做什么
举一个简单地例子,从最原始的遍历到最终使用Lambda表达式实现,可以轻而易举的发现Lambda表达式的优美与简洁。
现在有一个学生的集合数据,然后需要对这批数据进行处理,然后过滤出需要的数据
需求:
1、查询出年龄大约30的学生
2、查询出学费大于18000.99的学生
package com.weather.spring.cloud.initializrstart.dao;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.math.BigDecimal;
/**
* @program: msa-weather-master
* @description:
* @author: W.HL
* @create: 2019-04-24 20:33
**/
public @Data class Student
{
/**
* 姓名
*/
private String name;
/**
* 年龄
*/
private int age;
/**
* 学费
*/
private BigDecimal studyFee;
}
初始化一个数据集合
@Slf4j
public class LambdaTest
{
private static final int ageLit = 30;
private static final BigDecimal feeLit = new BigDecimal("18000.99");
List<Student> list = Arrays.asList(
new Student("赵敏",18,new BigDecimal("15000.11"))
,new Student("张无忌",20,new BigDecimal("16000.99"))
,new Student("周芷若",25,new BigDecimal("18000.99"))
,new Student("小昭",40,new BigDecimal("21000.99"))
,new Student("宋青书",50,new BigDecimal("31000.99"))
);
}
一、使用原始for循环进行过滤查询操作
/**
* 根据年龄过滤
* @param list
* @return
*/
public List<Student> filterStudentByAge(List<Student> list){
List<Student> resultList = new ArrayList<>();
for (Student student : list){
if(student.getAge()>ageLit){
resultList.add(student);
}
}
return resultList;
}
/**
* 根据学费过滤
* @param list
* @return
*/
public List<Student> filterStudentByFee(List<Student> list){
List<Student> resultList = new ArrayList<>();
for (Student student : list){
if(student.getStudyFee().compareTo(feeLit)>0){
resultList.add(student);
}
}
return resultList;
}
@Test
public void test(){
/*获取年龄大于30的学生*/
List<Student> list_1 = filterStudentByAge(list);
log.info("当前年龄大于30的学生有:{}",list_1.toString());
log.info("----------------------------------");
/*获取学费大于18000的学生*/
List<Student> list_2 = filterStudentByFee(list);
log.info("当前学费大大于18000.99元的学生有:{}",list_2.toString());
}
发现了很多冗余代码,于是进行了优化使用策略者模式进行优化处理
二、优化方案一:使用策略者模式进行优化处理
package com.weather.spring.cloud.initializrstart.service;
/**
* @program: msa-weather-master
* @description: This is a filer for student and return list
* @author: W.HL
* @create: 2019-04-24 20:59
**/
@FunctionalInterface
public interface FilterStudent<T>
{
boolean filterByCond(T t);
default void filterByCond3(T t){
System.out.println(t);
};
}
package com.weather.spring.cloud.initializrstart.service;
import com.weather.spring.cloud.initializrstart.dao.Student;
/**
* @program: msa-weather-master
* @description: This is filter student by age
* @author: W.HL
* @create: 2019-04-24 21:02
**/
public class FilterAgeStudentImpl implements FilterStudent<Student>
{
private static final int ageLit = 40;
@Override
public boolean filterByCond(Student student)
{
return student.getAge()>ageLit?true:false;
}
}
package com.weather.spring.cloud.initializrstart.service;
import com.weather.spring.cloud.initializrstart.dao.Student;
import java.math.BigDecimal;
/**
* @program: msa-weather-master
* @description: This is filter student by fee
* @author: W.HL
* @create: 2019-04-24 21:02
**/
public class FilterFeeStudentImpl implements FilterStudent<Student>
{
private static final BigDecimal feeLit = new BigDecimal("18000.99");
@Override
public boolean filterByCond(Student student)
{
return student.getStudyFee().compareTo(feeLit)>1?true:false;
}
}
使用是个过滤接口然后分别创建按照年龄过滤实现类、按照学费过滤实现类,编写相应测试方法;通过传递不同的实现类然后实现按照不同条件进行过滤,可以在不修改原来代码的基础上进行扩展过滤。
/**
* 优化一 使用策略者模式
*/
@Test
public void test1(){
/*获取年龄大于30的学生*/
List<Student> list_3 = filterByCond(list,new FilterAgeStudentImpl());
log.info("当前年龄大于30的学生有:{}",list_3.toString());
log.info("----------------------------------");
/*获取学费大于18000的学生*/
List<Student> list_4 = filterByCond(list,new FilterFeeStudentImpl());
log.info("当前学费大大于18000.99元的学生有:{}",list_4.toString());
}
public List<Student> filterByCond(List<Student> list,FilterStudent<Student> filterStudent){
List<Student> list_1 = new ArrayList<>();
for (Student student: list){
if(filterStudent.filterByCond(student)){
list_1.add(student);
}
}
return list_1;
}
三、优化方案二:使用Lambda表达式处理
/**
* 优化二 使用Lambda 表达式进行处理
*/
@Test
public void test2(){
/*获取年龄大于30的学生*/
List<Student> list_3 = filterByCond(list,(s) -> s.getAge()<=ageLit);
log.info("当前年龄大于30的学生有:{}",list_3.toString());
log.info("----------------------------------");
/*获取学费大于18000的学生*/
List<Student> list_4 = filterByCond(list,(s) -> s.getStudyFee().compareTo(feeLit)>0);
log.info("当前学费大于18000.99元的学生有:{}",list_4.toString());
}
可能也许不太明白什么意思,可以使用Debug端点进行查看详细,从下图可以看到Lambda表达式做执行的功能实际就是匿名函数大括号中所执行的内容,从而做到了在不使用具体实现类的情况下通过直接定义过滤条件实现过滤。
四、优化方案三:使用Lambda表达式中的 stream处理并进行排序处理
/**
* 优化三 使用Lambda stream表达式进行处理
*/
@Test
public void test3(){
/*获取年龄大于30的学生 并按照年龄倒叙*/
List<Student> list_3 = list.stream()
.filter((e)>e.getAge()>ageLit)
.sorted(Comparator.comparing(Student::getAge).reversed())
.collect(Collectors.toList());
log.info("当前年龄大于30的学生有:{}",list_3.toString());
log.info("----------------------------------");
/*获取学费大于18000的学生*/
List<Student> list_4 = list.stream()
.filter((e)->e.getStudyFee().compareTo(feeLit)>0)
.collect(Collectors.toList());
log.info("当前学费大于18000.99元的学生有:{}",list_4.toString());
}
需求更改:只查询出年龄小于30学生的学费,不要其他数据 (将过滤出的数据通过Map返回由应用给定结果组成的流)
/**
* 只获取年龄小于30的学生的学费
*/
@Test
public void test4(){
/*获取年龄大于30的学生*/
list.stream().filter(e->e.getAge()<30).map(e->e.getStudyFee()).forEach(e-> System.out.println(e));
log.info("----------------------------------");
}
Lambda表达式在数据过滤方面从上面可以很清晰的看出来原来需要将近10行的代码现在只要一行既能完成,缩减了大量的垃圾代码
Lambda语法总结:
jdk1.8中使用“->”操作符又称之为箭头操作符或者Lambda操作符,使用该操作符将表达式分为两部分:
左侧:Lambda表达式参数列表
右侧:Lambda表达式中所执行的功能(又称之为函数式接口具体实现方法)
接口方法参数情况总结
参数以及返回值情况
无参数无返回值 | |
有一个参数无返回值(左边括号可以省略) | |
有多个参数有返回值(Lambda体中只有一条语句,return和大括号都可以省略) | |
如果上下文中指定参数类型则Lambda参数列表中可以省略参数类型,JVM会根据上下文自动识别参数类型 | |
函数式接口: 接口添加@FunctionalInterface注解,只能含有一个抽象方法但是可以同时含有多个被default修饰的方法,被default修饰的方法实现类可以选择不实现但是仍然可以直接调用使用
@FunctionalInterface
public interface FilterStudent<T>
{
boolean filterByCond(T t);
// 如果在创建一个抽象接口 例如:boolean filterByCond5(T t);则会报错
default void filterByCond3(T t){
System.out.println(t);
};
}
java8之前就存在许多比如我们最常用的 Comparator<T>、Runable、Consumer<T>等