近期的开发工作中,遇到一个需求: 对 Listmap的结果集进行排序,类似于模拟 数据库中的Order By 排序。那么主要的需求有: 排序方式 ASC/DESC ; null 值处理:NULL FIRST / NULL LAST 。 在Java 中要实现以上相应的功能,对List进行排序,会遇到对应问题: 元素中有 null ,排序时候会抛出 NPE 、 null 元素放在 最前、最后面的问题。
本文将基于Java8,逐一演示,上述中出现问题的对应示例代码;最终给出 List
1、元素有null,排序处理:
- /**
- * Description: null 值处理
- *
1. null 元素,排序 NPE - *
2. 解决: null 放在最前面、最后面 - * @param
- * @return void
- * @version v1.0
- * @author wu
- * @date 2022/10/17 15:43
- */
- @Test
- public void nullListTest(){
- ArrayList
list = Lists.newArrayList("22","33",null,"11"); - System.out.println("nullListTest 排序前:" + list);
- // list中有 null 元素,排序会抛出 NPE
- list.sort(Comparator.comparing(e->e)); // 抛出 NPE
- list.sort((e1,e2)->e1.compareTo(e2)); // 抛出 NPE
- // list.sort(Comparator.comparing(String::valueOf)); // 避免npe
-
- // null 值处理: null 放在最前
- list.sort(Comparator.comparing(e->e,Comparator.nullsFirst(String::compareTo)));
- System.out.println("nullListTest 排序后: null 放在最前:" + list);
-
- // null 值处理: null 放在最后
- list.sort(Comparator.comparing(e->e,Comparator.nullsLast(String::compareTo)));
- System.out.println("nullListTest 排序后:null 放在最后:" + list);
- }
1.1、输出结果:
- nullListTest 排序前:[22, 33, null, 11]
-
- java.lang.NullPointerException
- ...
2、倒序 DESC时,null 值放在 最前面、最后面的处理
- /**
- * Description: 倒序的时候, null 值处理
- *
1. null 最前面: nullsLast 方法 - *
2. null 最后面: nullsFirst 方法 - * @return void
- * @version v1.0
- * @author wu
- * @date 2022/10/17 16:37
- */
- @Test
- public void nullDESCTest() throws Exception{
- ArrayList
list = Lists.newArrayList("22","33",null,"11"); - System.out.println("nullDESCTest 排序前:" + list);
-
- // DESC , null first
- // list.sort(Comparator.comparing((String e)->e,Comparator.nullsFirst(String::compareTo)).reversed());
- list.sort(Comparator.comparing((String e)->e,Comparator.nullsLast(String::compareTo)).reversed());
- System.out.println("nullDESCTest DESC , null first :" + list);
-
- // DESC , null last
- list.sort(Comparator.comparing((String e)->e,Comparator.nullsFirst(String::compareTo)).reversed());
- System.out.println("nullDESCTest DESC , null last :" + list);
-
- }
2.1、输出结果:
- nullDESCTest 排序前:[22, 33, null, 11]
- nullDESCTest DESC , null first :[null, 33, 22, 11]
- nullDESCTest DESC , null last :[33, 22, 11, null]
3、数字是字符串类型时,排序不对的问题:
- /**
- * Description: 字符串类型数字 排序
- *
解决:字符串转换为数字,进行排序 - * @return void
- * @version v1.0
- * @author wu
- * @date 2022/10/17 15:44
- */
- @Test
- public void strNumTest() throws Exception{
- List
list = Lists.newArrayList("10","11","101","111"); - System.out.println("strNumTest 排序前:" + list);
-
- // 倒序排序
- list.sort(Comparator.comparing(String::valueOf).reversed());
- // list.sort(Comparator.comparing((String e)->Integer.valueOf(e)).reversed()); // 解决排序不对的问题
- System.out.println("strNumTest 排序后:" + list);
-
- }
3.1、输出结果是:
- strNumTest 排序前:[10, 11, 101, 111]
- strNumTest 排序后:[111, 11, 101, 10]
1、上述代码中,演示了可能出现的问题,以及对应的解决方案:
2、List
3、经整理汇总后,通用排序流程如下:
4、定义一个 ListMapConfig 配置类 ,统一维护相关的配置:
- /**
- * Description: List Map 排序 配置
- * @author w
- * @version 1.0
- * @date 2022/10/17 16:09
- */
- public class ListMapConfig {
-
- private String orderProperty ; // 排序字段:
- private String porpertyType = "STRING"; // 属性类型: STRING / NUMBER
- private String orderMode ="ASC"; // 排序方式: ASC/DESC
- private String orderModeNull ="LAST"; // null值处理: FIRST / LAST
-
- public static ListMapConfig getDefault(){
- return new ListMapConfig();
- }
- // ignore getter / setter
- }
5、通用的 ListMap排序方法:
- public static void processSort(List{
- String orderProperty = config.getOrderProperty();
- Assert.isTrue(StringUtils.isNotBlank(orderProperty));
-
- if("NUMBER".equals(config.getPorpertyType())){
- // 数字 类型排序
- if("DESC".equals(config.getOrderMode())){
- if("FIRST".equals(config.getOrderModeNull())){
- listMap.sort(Comparator.comparing((Map e)->{
- Object val = e.get(orderProperty);
- return val == null ? null : Double.valueOf(val.toString());
- // 倒序时,null值放在最后,反过来:需要用 nullsLast
- },Comparator.nullsLast(Double::compareTo)).reversed());
- }else {
- listMap.sort(Comparator.comparing((Map e)->{
- Object val = e.get(orderProperty);
- return val == null ? null : Double.valueOf(val.toString());
- // 倒序时,null值放在最后,反过来:需要用 nullsFirst
- },Comparator.nullsFirst(Double::compareTo)).reversed());
- }
- }else {
- if("FIRST".equals(config.getOrderModeNull())){
- listMap.sort(Comparator.comparing((Map e)->{
- Object val = e.get(orderProperty);
- return val == null ? null : Double.valueOf(val.toString());
- },Comparator.nullsFirst(Double::compareTo)));
- }else {
- listMap.sort(Comparator.comparing((Map e)->{
- Object val = e.get(orderProperty);
- return val == null ? null : Double.valueOf(val.toString());
- },Comparator.nullsFirst(Double::compareTo)));
- }
- }
- }else if("STRING".equals(config.getPorpertyType())){
- // 字符串 类型排序
- if("DESC".equals(config.getOrderMode())){
- if("FIRST".equals(config.getOrderModeNull())){
- listMap.sort(Comparator.comparing((Map e) -> {
- Object val = e.get(orderProperty);
- return null == val ? null : val.toString();
- // 倒序时,null值放在最后,反过来:需要用 nullsLast
- },Comparator.nullsLast(String::compareTo)).reversed());
- }else {
- listMap.sort(Comparator.comparing((Map e) -> {
- Object val = e.get(orderProperty);
- return null == val ? null : val.toString();
- // 倒序时,null值放在最后,反过来:需要用 nullsFirst
- },Comparator.nullsFirst(String::compareTo)).reversed());
- }
- }else {
- if("FIRST".equals(config.getOrderModeNull())){
- listMap.sort(Comparator.comparing((Map e) -> {
- Object val = e.get(orderProperty);
- return null == val ? null : val.toString();
- },Comparator.nullsFirst(String::compareTo)));
- }else {
- listMap.sort(Comparator.comparing((Map e) -> {
- Object val = e.get(orderProperty);
- return null == val ? null : val.toString();
- },Comparator.nullsLast(String::compareTo)));
- }
- }
- }
- }
1、创建一个 ListMapSortTest2 测试类:
- public class ListMapSortTest2 {
-
- static List
orderList = null; - static List
-
- public static void main(String[] args) {
- init();
- System.out.println(orderList);
-
- // 1、转换为map
- listMap = com.google.common.collect.Lists.newArrayList();
- for (Order e : orderList) {
- JSONObject jsonObject = JSON.parseObject(JSON.toJSONString(e));
- Map map = JSON.toJavaObject(jsonObject, Map.class);
- listMap.add(map);
- }
- System.out.println("listMap :"+listMap);
-
- ListMapConfig config = ListMapConfig.getDefault();
- config.setOrderProperty("appNo");
-
- // STRING-TEST1: ASC - NULL FIRST
- config.setOrderModeNull("FIRST");
- processSort(listMap,config);
- System.out.println("STRING-TEST1: ASC - NULL FIRST : " + listMap);
-
- // STRING-TEST2: ASC - NULL LAST
- config.setOrderModeNull("LAST");
- processSort(listMap,config);
- System.out.println("STRING-TEST2: ASC - NULL LAST : " + listMap);
-
- // STRING-TEST3: DESC - NULL FIRST
- config.setOrderModeNull("FIRST");
- config.setOrderMode("DESC");
- processSort(listMap,config);
- System.out.println("STRING-TEST3: DESC - NULL FIRST : " + listMap);
-
- // STRING-TEST4: DESC - NULL LAST
- config.setOrderModeNull("LAST");
- config.setOrderMode("DESC");
- processSort(listMap,config);
- System.out.println("STRING-TEST4: DESC - NULL LAST : " + listMap);
-
- }
-
- private static void init() {
- orderList = Lists.newArrayList();
- orderList.add(new Order(1,"小明","203"));
- orderList.add(new Order(2,"小红",null));
- orderList.add(new Order(3,"小刚","404"));
- }
-
- static class Order {
- private Integer id;
- private String name;
- private String appNo;
-
- public Order(Integer id, String name, String appNo) {
- this.id = id;
- this.name = name;
- this.appNo = appNo;
- }
-
- public Order() {
- }
-
- public Integer getId() {
- return id;
- }
-
- public void setId(Integer id) {
- this.id = id;
- }
-
- public String getName() {
- return name;
- }
-
- public void setName(String name) {
- this.name = name;
- }
-
- public String getAppNo() {
- return appNo;
- }
-
- public void setAppNo(String appNo) {
- this.appNo = appNo;
- }
-
- @Override
- public String toString() {
- return "Order{" +
- "id=" + id +
- ", name='" + name + '\'' +
- ", appNo='" + appNo + '\'' +
- '}';
- }
- }
- }
3、注意:Number类型,未测试!
1、本文初步解决 List
2、ListMapConfig 类中,porpertyType 等属性,可以定义为 枚举类型, 便于更好的理解,和后续扩展。
3、通用排序方法:processSort , 写了太多的 if else , 可以引入设计模式,更加优雅!
排序相关的文章资料参考:
使用MySQL FIELD函数实现自定义排序 特定字段排序 指定字段排序_HaHa_Sir的博客-CSDN博客
Java List集合排序 Java8 List集合排序方法 Java Lambda集合排序_HaHa_Sir的博客-CSDN博客_java8 集合排序
Oracle 中文排序 Oracle 中文字段排序_HaHa_Sir的博客-CSDN博客_oracle 中文排序