java中lambda接口一览

发布时间 2023-06-12 00:51:37作者: 时间羚羊

1、java中标准定义的用于操作数据的lambda接口都在 package java.util.function; 这个包里面,这些接口都不是用来给你在别的类里面实现的,虽然实现了也没什么关系。

2、lambda的写法实际上是逆反面向对象编程这种思想的,因为在编程中它直接提现了数据的处理的逻辑。

之所有多数语言支持还要有这个功能,我想一方面不管什么样的规范,过于彻底的遵循反而不美,毕竟语言作为工具而言,能打最为重要。

而且在很多的数据分析和处理的代码模块中,这种写法确实很香。

3、lambda最基本的四件套:

接口名 描述  方法
Supplier 提供者,用来返回数据  
Consumer 消费者,用来传入数据  
Predicate 断言或者说判断  
Function 功能或者对数据的操作组装等等  

 

基于这四个接口,java实现了自己的一套操作数据的功能,比如stream里面那些方法,我们也可以基于这四个接口实现自己的一套数据处理流程。

那我们写一个实际的例子,现在有五个人的姓名和身份证号,要按计算他们年龄并且从小到大排序,未满18岁的和大于35岁的我们不要。

解决:我们先构造一个Person类:

@NoArgsConstructor
@AllArgsConstructor
@Data
public class Person {
    private String name;
    private String identifyCardNum;

    private int age;
}

使用上面四个基础lambda接口解决这个问题:

package com.local.lambda;

import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.*;
import java.util.concurrent.TimeUnit;
import java.util.function.Consumer;
import java.util.function.Function;
import java.util.function.Predicate;
import java.util.function.Supplier;

public class Main {

public static Map<String, Object> buildMap(String name, String identifyCardNum) {
Supplier<Map<String, Object>> supplier = HashMap::new;
Map<String, Object> map = supplier.get();
map.put("name", name);
map.put("identifyCardNum", identifyCardNum);
return map;
}

public static void main(String[] args) {

List<Map<String, Object>> personMapList = new ArrayList<Map<String, Object>>() {{
add(buildMap("张三", "32108119850606"));

add(buildMap("李四", "32108119980806"));

add(buildMap("王五", "32108120011006"));

add(buildMap("钱六", "32108120031206"));

add(buildMap("孙七", "32108120091206"));
}};

List<Person> compose = compose(personMapList, pmList -> {
List<Person> personList = new ArrayList<>();
for (Map<String, Object> map : pmList) {
Person person = new Person();
int age = calcAge((String) map.get("identifyCardNum"));
person.setAge(age);
person.setName((String) map.get("name"));

if(age >= 35 || age <= 18) {
continue;
}

personList.add(person);
}
return personList;
});

Comparator<Person> comparator = Comparator.comparingInt(Person::getAge);
compose.sort(comparator);

printPersonList(compose);
}

static List<Person> compose(List<Map<String, Object>> personMapList, Function<List<Map<String, Object>>, List<Person>> composeFun) {
return composeFun.apply(personMapList);
}

/**
* 打印结果
* @param personList
*/
static void printPersonList(List<Person> personList) {
Consumer<Person> consumer = p -> {
System.out.println("[" +
"name: " + p.getName() + ","
+ "age: " + p.getAge()
+ "]");
};
for(Person person : personList) {
consumer.accept(person);
}
}

private static int calcAge(String identifyCardNum) {
Predicate<String> emptyPredicate = s -> s == null || "".equals(s);
Predicate<String> acceptablePredicate = s -> s.length() < 14;

if(emptyPredicate.and(acceptablePredicate).test(identifyCardNum)) {
throw new RuntimeException("not a acceptable identifyCardNum");
}

Function<String, String> birthNumFun = s -> s.substring(6);

Function<String, Date> birthNumToDateFun = s -> {
SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyyMMdd");
Date parse = null;
try {
parse = simpleDateFormat.parse(s);
} catch (ParseException e) {
e.printStackTrace();
}
return parse;
};

Function<Date, Integer> calAgeFun = d -> {
Calendar birthCal = Calendar.getInstance();
birthCal.setTime(d);

Calendar nowCal = Calendar.getInstance();
nowCal.setTime(new Date());

long diffInMillis = nowCal.getTimeInMillis() - birthCal.getTimeInMillis();
long diffInDays = TimeUnit.DAYS.convert(diffInMillis, TimeUnit.MILLISECONDS);

return (int) diffInDays / 365;
};

return birthNumFun.andThen(birthNumToDateFun).andThen(calAgeFun).apply(identifyCardNum);
}

}

 结果:

[name: 钱六,age: 19]
[name: 王五,age: 21]
[name: 李四,age: 24]

Process finished with exit code 0

 

 

PS:

1、Function接口中的compose和andThen区别:

compose先执行调用链右侧逻辑,再执行左侧逻辑;

andThen先执行左侧逻辑,再执行右侧逻辑;

最好别混用。

 

2、通常Consumer可以用来定义自己的增强for循环方法,Supplier则是构建者和工厂模式中用的多,还是蛮好用的。

因为有些大公司是有代码的sonar检查和人工复审的。new和for循环嵌套都会被检测为糟糕代码,这俩东西相当实用!