java中lambda接口一览
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循环嵌套都会被检测为糟糕代码,这俩东西相当实用!