Java 8 获取ISO8601格式生日Person列表中最年轻人员的方法
问题场景
现有不可修改的Person类定义如下:
class Person { String name; String id; String dateOfBirth; int salary; } List<Person> listOfPersons; // 列表已预填充业务数据
已知约束如下:
dateOfBirth字段为ISO8601格式字符串,示例值:"2018-12-10T13:49:51.141Z"- 可通过
Date.from(Instant.parse(dateOfBirth))将该字段转换为java.util.Date类型,出生日期越晚,对应人员年龄越小 - 需求:基于Java 8 Stream流或其他优雅方案,从已填充数据的人员列表中获取年龄最小的
Person对象
实现方案
方案1:Java 8 Stream 原生实现(性能最优)
直接通过Stream的max()方法单次遍历列表即可拿到结果,时间复杂度O(n),不需要对全表做排序,是最推荐的实现方式:
// 空列表场景会返回异常,可根据业务需求调整默认值处理逻辑 Person youngestPerson = listOfPersons.stream() .max(Comparator.comparing(p -> Date.from(Instant.parse(p.dateOfBirth)))) .orElseThrow(() -> new IllegalArgumentException("人员列表不能为空"));
*优化提示:如果列表数据量很大,为了避免每次比较时重复解析日期字符串,可以先将解析后的日期做一次缓存映射,减少重复计算:
Person youngestPerson = listOfPersons.stream() .collect(Collectors.toMap( p -> p, p -> Date.from(Instant.parse(p.dateOfBirth)) )) .entrySet() .stream() .max(Map.Entry.comparingByValue()) .map(Map.Entry::getKey) .orElseThrow(() -> new IllegalArgumentException("人员列表不能为空"));
方案2:集合工具类实现(无Stream依赖场景适用)
如果运行环境不支持Java 8 Stream,可直接使用JDK原生的Collections.max方法实现,逻辑与Stream方案一致,同样为单次遍历取最值:
if (listOfPersons == null || listOfPersons.isEmpty()) { throw new IllegalArgumentException("人员列表不能为空"); } Person youngestPerson = Collections.max( listOfPersons, Comparator.comparing(p -> Date.from(Instant.parse(p.dateOfBirth))) );
避坑说明
不要为了取单个最值对全列表做排序,类似如下写法性能很差,不推荐使用:
// 反例:全量排序时间复杂度O(nlogn),数据量大时性能损耗明显 Person youngestPerson = listOfPersons.stream() .sorted(Comparator.comparing((Person p) -> Date.from(Instant.parse(p.dateOfBirth))).reversed()) .findFirst() .orElseThrow(() -> new IllegalArgumentException("人员列表不能为空"));
取单个最值的场景下,全排序做了大量无意义的计算,性能远低于直接遍历取最值的实现。
内容的提问来源于stack exchange,提问作者Vanja Radovanovic
相关产品推荐
相关产品推荐

