一、产生
Java1.8的新特性,也是最主要的特性,允许把函数作为一个方法的参数(函数作为参数传递进方法中)。
二、Lambda出世原因
先看一个例子:
@Test
void testLambdaThread(){
// 匿名内部类
Runnable runnable= new Runnable(){
@Override
public void run() {
System.out.println("hello world");
}
};
// 启动一个线程去执行
new Thread(runnable).start();
}
这里首先创建了一个匿名内部类Runnable,这个匿名内部类有且只有一个执行方法run(),我们覆盖了方法体,如果不是匿名内部类,我们需要自己去写一个实现类,这样是不是很麻烦,代码繁杂;
那我们可以想象一下,这个接口如果是某一个函数(假设函数为A)的参数,而这个接口,只有一个方法(实现类只需要重写这个方法),我们可不可以直接往A的参数里写这个方法体,函数便可以识别该接口的方法并执行(由编译器去帮我们编译产生相同效果的class)。
于是上述线程可使用lambda表达式:
new Thread(()-> System.out.println("hello world"));
三、Lambda表达式语法
(parameters) -> expression
或
(parameters) ->{ statements; }
一些参数 一个箭头 一段代码
标准格式:
(参数类型 参数名称) ‐> { 代码语句 }
parameters 顾名思义,方法体的参数,这里可无需声明参数类型,如果是一个参数,可省略括号();
p->p.getId(); (Person a ,Person b)->a.getSalary().compareTo(b.getSalary())
expression 如果执行方法体较为简单,使用一个表达式即可! 省略{};
statements 如方法体实现代码量较多,实现逻辑使用{};
上面应该不难理解,这是语法,接下来实操
1.无参无返回
见上线程的lambda表达式
2. 有参有返回(重点分析)
下面举例演示java.util.Comparator 接口的使用场景代码,其中的抽象方法定义为:
public abstract int compare(T o1, T o2);
当需要对一个对象数组进行排序时, Arrays.sort 方法需要一个Comparator 接口实例来指定排序的规则。
上代码
public class Person {
private String name;
private int age;
}
传统写法
import java.util.Arrays;
import java.util.Comparator;
public class Demo06Comparator {
public static void main(String[] args) {
Person[] array = {
new Person("叶存星福", 29),
new Person("李春华", 31),
new Person("叶海祥", 60) };
// 匿名内部类
Comparator<Person> comparator = new Comparator<Person>() {
@Override
public int compare(Person people1, Person people2) {
return people1.getAge() ‐ people2.getAge();
}};
Arrays.sort(array, comparator ); // comparator 为 Comparator接口实例
for (Person person : array) {
System.out.println(person);
}
}
}
分析
- 为了排序, Arrays.sort 方法需要排序规则,即Comparator 接口的实例,抽象方法compare 是关键;
- 为了指定compare 的方法体,不得不需要Comparator 接口的实现类;
- 为了省去定义一个ComparatorImpl 实现类的麻烦,不得不使用匿名内部类;
- 必须覆盖重写抽象compare 方法,所以方法名称、方法参数、方法返回值不得不再写一遍,且不能写错;
实际上,只有参数和方法体才是关键。
Lambda表达式
Arrays.sort(array, (Person a, Person b) ‐> {
return a.getAge() ‐ b.getAge();
});
for (Person person : array) {
System.out.println(person);
}
3.无参有返回
与上述几乎一致,上代码:
/**
* @author yecxf
* @created time 2020/10/17 10:11
*/
public interface Invocation {
// 唯一获取结果方法
Object getResult();
}
接口作为另一方法的入参
/**
* @author yecxf
* @created time 2020/10/17 10:13
*/
public class CacheOperator {
public Object doCache(String key,Integer ExpireTime,Invocation invocation){
/**
* 假设这里是存储缓存操作
*/
return null;
}
}
Dao层或Service层返回结果入缓存
public ResultInfo getNpsInfo(){
cacheOperator.doCache("helloLambda",10*60,()->npsDao.getNpsInfo());
return null;
}
四、使用Lambda表达式条件
使用Lambda必须具有接口,且要求接口中有且仅有一个抽象方法。无论是JDK内置的Runnable 、Comparator 接口还是自定义的接口,只有当接口中的抽象方法存在且唯一时,才可以使用Lambda。
使用Lambda必须具有上下文推断。也就是方法的参数或局部变量类型必须为Lambda对应的接口类型,才能使用Lambda作为该接口的实例。
五、实际应用场景
1. List集合使用场景
新建一个list
NpsInfo npsInfo = new NpsInfo("北京银行", (float) 458484845415L);
NpsInfo npsInfo1 = new NpsInfo("深圳银行", (float) 4584848451415L);
NpsInfo npsInfo2 = new NpsInfo("工商银行", (float) 45848484445415L);
NpsInfo npsInfo3 = new NpsInfo("建设银行", (float) 45848544845415L);
List<NpsInfo> npsInfoList = new ArrayList<NpsInfo>(){{
add(npsInfo);
add(npsInfo1);
add(npsInfo2);
add(npsInfo3);
}};
- 遍历
// 遍历操作
npsInfoList.parallelStream().forEach(p-> System.out.println(p.getDepartmentName()));
//等价于
npsInfoList.parallelStream().forEach((NpsInfo nps)-> System.out.println(nps.getDepartmentName()));
- 过滤
// 过滤操作
List<NpsInfo> filterNpsInfos = npsInfoList.parallelStream().filter(p -> "深圳银行".equals(p.getDepartmentName())).collect(Collectors.toList());
filterNpsInfos.forEach(p-> System.out.println(p.getDepartmentName()));
- 排序
// 排序操作
List<NpsInfo> sortedNpsInfo = npsInfoList.parallelStream().sorted(Comparator.comparing(NpsInfo::getDepartmentScore)).collect(Collectors.toList());
sortedNpsInfo.forEach(p-> System.out.println(p.getDepartmentName()));
- 校验
// 校验, 符合返回true
boolean b = npsInfoList.parallelStream().allMatch(p -> "hello world".equals(p.getDepartmentName()));
- 某个字段存放到Set集合中
- // 存放到Set集合中
Set<Float> npsInfoScoreSet = npsInfoList.parallelStream().map(p -> p.getDepartmentScore()).collect(Collectors.toSet());
Iterator<Float> iterator = npsInfoScoreSet.iterator();
while(iterator.hasNext()){
System.out.println(iterator.next());
}
2. Json格式数据
实际开发中有这种场景,请求接口成功后,需对返回数据做校验,成功后才会给到前端,如何快速校验呢;
JSONArray和List功能一致,记住就OK~
// 模拟接口返回
public static String getRequest(List<NpsInfo> list){
HashMap<String, Object> hashMap = new HashMap<>();
hashMap.put("responseCode","000000");
hashMap.put("msg","返回成功");
hashMap.put("data", JSONArray.toJSONString(list));
return JSONArray.toJSONString(hashMap);
}
// 过滤
// 假设这是请求成功返回的数据
String responseDada = getRequest(npsInfoList);
JSONObject jsonObject = (JSONObject) JSON.parse(responseDada);
String data = (String) jsonObject.get("data");
JSONArray jsonArray = (JSONArray) JSONArray.parse(data);
List<JSONObject> departmentName = jsonArray.parallelStream().map(p -> (JSONObject) p).filter(p -> "深圳银行".equals(p.getString("departmentName"))).collect(Collectors.toList());