• Java中List的排序


    场景

    Bean定义如下,仅有一个类型为Integerage字段。

    @NoArgsConstructor
    @AllArgsConstructor(staticName = "of")
    @Data
    public static class Employee {
        private Integer age;
    }     
    

    列表初始化5个元素:

    List<Employee> list = new ArrayList<>();
    list.add(Employee.of(21));
    list.add(Employee.of(22));
    list.add(Employee.of(25));
    list.add(Employee.of(28));
    list.add(Employee.of(23));           
    

    排序

    使用Collections中的sort方法进行排序:

    Collections.sort(list, new Comparator<Employee>() {
        @Override
        public int compare(Employee o1, Employee o2) {
            return o1.getAge().compareTo(o2.getAge());
        }
    });
    

    倒序:

    Collections.reverse(list);
    

    lambda表达式

    JDK8支持lambda表达式,写法更加简洁:

    Collections.sort(list, (o1, o2) -> o1.getAge().compareTo(o2.getAge()));
    

    或者使用Comparator接口:

    Collections.sort(list, Comparator.comparing(Employee::getAge));
    

    倒序:

    Collections.sort(list, Comparator.comparing(Employee::getAge).reversed());
    

    stream的sorted方法

    list.stream().sorted(Comparator.comparing(Employee::getAge));
    

    倒序:

    list.stream().sorted(Comparator.comparing(Employee::getAge).reversed());
    

    list自带的sort方法

    list.sort(Comparator.comparing(Employee::getAge));
    

    倒序:

    list.sort(Comparator.comparing(Employee::getAge).reversed());
    

    null值

    假设列表中有age字段为null:

    List<Employee> list = new ArrayList<>();
    list.add(Employee.of(21));
    list.add(Employee.of(null));
    list.add(Employee.of(null));
    list.add(Employee.of(28));
    list.add(Employee.of(23));           
    

    这个时候会报NPE:

    -----------------------------
    Exception in thread "main" java.lang.NullPointerException
    	at java.util.Comparator.lambda$comparing$77a9974f$1(Comparator.java:469)
    	at java.util.TimSort.countRunAndMakeAscending(TimSort.java:355)
    	at java.util.TimSort.sort(TimSort.java:220)
    	at java.util.Arrays.sort(Arrays.java:1512)
    	at java.util.ArrayList.sort(ArrayList.java:1462)
    

    可以使用Comparator.comparing的第2个参数:

    list.sort(Comparator.comparing(Employee::getAge, Comparator.nullsLast(Comparator.naturalOrder())));
    list.sort(Comparator.comparing(Employee::getAge, Comparator.nullsLast(Integer::compareTo)));
    list.sort(Comparator.comparing(Employee::getAge, Comparator.nullsLast(Comparable::compareTo)));
    

    以上3中写法都可以,注意第2个参数使用了Comparator.nullsLast让null排在最后。
    与之对应的是Comparator.nullsFirst可以null排在最前。

    任意字段排序

    最近项目中有个这样场景,List中是个Map<String, Object>,需要支持Map的任意key排序。
    完整代码如下:

    import java.util.*;
    
    /**
     * @author cdfive
     * @date 2019-05-26
     */
    public class ListSortDemo2 {
        public static void main(String[] args) {
            List<Map<String, Object>> list = new ArrayList<>();
            list.add(new HashMap<String, Object>(){{put("name", "aaa");put("age", 21);}});
            list.add(new HashMap<String, Object>(){{put("name", "ccc");put("age", null);}});
            list.add(new HashMap<String, Object>(){{put("name", "ddd");put("age", null);}});
            list.add(new HashMap<String, Object>(){{put("name", "bbb");put("age", 28);}});
            list.add(new HashMap<String, Object>(){{put("name", "aaa");put("age", 23);}});
    
            printList(list);
    
            printLineSep();
    
            sort(list, "age", "asc");
    
            printList(list);
        }
    
        public static void sort(List<Map<String, Object>> list, String sortField, String sortDirection) {
            if ("desc".equals(sortDirection)) {
                Comparator<Map<String, Object>> comparator = Comparator.comparing(o -> (Comparable) o.get(sortField), Comparator.nullsFirst(Comparable::compareTo));
                list.sort(comparator.reversed());
            } else {
                Comparator<Map<String, Object>> comparator = Comparator.comparing(o -> (Comparable) o.get(sortField), Comparator.nullsLast(Comparable::compareTo));
                list.sort(comparator);
            }
        }
    
        public static void printList(List<?> list) {
            list.stream().forEach(o -> System.out.print(o));
            System.out.println();
        }
    
        public static void printLineSep() {
            System.out.println("-----------------------------");
        }
    }
    

    注意:
    倒序使用Comparator.nullsFirstcomparator.reversed(),需要单独定义comparator变量,如果直接一行写:
    list.sort(Comparator.comparing(o -> (Comparable) o.get(sortField), Comparator.nullsFirst(Comparable::compareTo)).reversed());会编译不通过。
    正序使用Comparator.nullsLast

    正序null在后面,倒序null在前面,可以这样写:

    public static void sort2(List<Map<String, Object>> list, String sortField, String sortDirection) {
        Comparator<Map<String, Object>> comparator = Comparator.comparing(new Function<Map<String, Object>, Comparable>() {
            @Override
            public Comparable apply(Map<String, Object> map) {
                Object obj = map.get(sortField);
    
                if (obj instanceof Comparable) {
                    return (Comparable) obj;
                }
    
                if (obj == null) {
                    return null;
                }
    
                throw new UnsupportedOperationException("无法排序的字段=" + sortField);
            }
        }, Comparator.nullsLast(Comparator.naturalOrder()));
    
        if ("desc".equals(sortDirection)) {
            list.sort(comparator.reversed());
        } else {
            list.sort(comparator);
        }
    }
    
  • 相关阅读:
    spring源码下载
    java资料共享
    《Linux命令行与shell脚本编程大全》读书笔记
    《微服务设计》读书笔记
    tornado关于AsyncHTTPClient的使用笔记
    java stackoverflowerror与outofmemoryerror区别(转)
    JAVA关于泛型的笔记
    在JAVA中返回类型使用泛型T和Object有什么区别?
    《构架师的12项修炼》读书笔记
    关于控制台输入的代码怎么跑单元测试的问题记录
  • 原文地址:https://www.cnblogs.com/cdfive2018/p/10927960.html
Copyright © 2020-2023  润新知