美文网首页
Java8 - 对集合排序

Java8 - 对集合排序

作者: liuliuzo | 来源:发表于2020-11-09 13:38 被阅读0次

    对List进行排序

    当我们需要对集合的元素进行排序的时候,可以使用java.util.Comparator 创建一个比较器来进行排序。Comparator接口同样也是一个函数式接口,我们可以把使用lambda表达式。如下示例

    public class ComparatorLearn {
        public static void main(String[] args) {
            Employee e1 = new Employee("John", 25, 3000, 9922001);
            Employee e2 = new Employee("Ace", 22, 2000, 5924001);
            Employee e3 = new Employee("Keith", 35, 4000, 3924401);
            
            List<Employee> employees = new ArrayList<>();
            employees.add(e1);
            employees.add(e2);
            employees.add(e3);
    
            /**
             *     @SuppressWarnings({"unchecked", "rawtypes"})
             *     default void sort(Comparator<? super E> c) {
             *         Object[] a = this.toArray();
             *         Arrays.sort(a, (Comparator) c);
             *         ListIterator<E> i = this.listIterator();
             *         for (Object e : a) {
             *             i.next();
             *             i.set((E) e);
             *         }
             *     }
             *
             *     sort 对象接收一个 Comparator 函数式接口,可以传入一个lambda表达式
             */
            System.out.println("################");
            employees.sort((o1, o2) -> o1.getName().compareTo(o2.getName()));
            Collections.sort(employees, (o1, o2) -> o1.getName().compareTo(o2.getName()));
            employees.forEach(System.out::println);
            
            /**
             * Comparator.comparing 方法的使用
             * comparing 方法接收一个 Function 函数式接口 ,通过一个 lambda 表达式传入
             */
            System.out.println("################");
            employees.sort(Comparator.comparing(e -> e.getName()));
            employees.forEach(System.out::println);
    
            /**
                         *   该方法引用 Employee::getAge 可以代替 lambda表达式
             */
            System.out.println("################");
            employees.sort(Comparator.comparing(Employee::getAge));
            employees.forEach(System.out::println);
            
            /**
                         *    相反的排序规则
             */
            System.out.println("################");
            Collections.sort(employees, Comparator.comparing(Employee::getName).reversed());
            employees.forEach(System.out::println);
            
            /**
                         *    使用 Comparator.thenComparing 排序
             */
            System.out.println("################");
            Collections.sort(employees, Comparator.comparing(Employee::getAge).thenComparing(Employee::getName));
            employees.forEach(System.out::println);
            
            /**
             * 使用 Comparator.nullsFirst进行排序
             */
            System.out.println("################");
            employees.add(null);
            Collections.sort(employees, Comparator.nullsFirst(Comparator.comparing(Employee::getName)));
            employees.forEach(System.out::println);
    
            /**
             * 使用 Comparator.nullsLast进行排序
             */
            System.out.println("################");
            Collections.sort(employees, Comparator.nullsLast(Comparator.comparing(Employee::getName)));
            employees.forEach(System.out::println);
        }
    }
    
    public class Employee {
    
        String name;
        int age;
        double salary;
        long mobile;
    
        // constructors, getters & setters
    
        public Employee(String name, int age, double salary, long mobile) {
            this.name = name;
            this.age = age;
            this.salary = salary;
            this.mobile = mobile;
        }
    
        public String getName() {
            return name;
        }
    
        public void setName(String name) {
            this.name = name;
        }
    
        public int getAge() {
            return age;
        }
    
        public void setAge(int age) {
            this.age = age;
        }
    
        public double getSalary() {
            return salary;
        }
    
        public void setSalary(double salary) {
            this.salary = salary;
        }
    
        public long getMobile() {
            return mobile;
        }
    
        public void setMobile(long mobile) {
            this.mobile = mobile;
        }
    
        @Override
        public String toString() {
            return "Employee [name=" + name + ", age=" + age + ", salary=" + salary + ", mobile=" + mobile + "]";
        }
    }
    

    对Map进行排序

    在讲解Map排序之前,我们先来稍微了解下map,map是键值对的集合接口,它的实现类主要包括:HashMap, TreeMap, Hashtable以及LinkedHashMap等。其中这四者的区别如下(简单介绍):
    HashMap:我们最常用的Map,HashMap是无序的,它根据key的HashCode 值来存储数据,根据key可以直接获取它的Value,同时它具有很快的访问速度。HashMap最多只允许一条记录的key值为Null(多条会覆盖);允许多条记录的Value为 Null。非同步的。
    TreeMap:能够把它保存的记录根据key排序,默认是按升序排序,也可以指定排序的比较器,当用Iterator 遍历TreeMap时,得到的记录是排过序的。TreeMap不允许key的值为null。非同步的。
    Hashtable:与HashMap类似,不同的是:key和value的值均不允许为null;它支持线程的同步,即任一时刻只有一个线程能写Hashtable, 因此也导致了Hashtale在写入时会比较慢。
    LinkedHashMap:LinkedHashMap是有序的,保存了记录的插入顺序,在用Iterator遍历LinkedHashMap时,先得到的记录肯定是先插入的.在遍历的时候会比HashMap慢。key和value均允许为空,非同步的。

    Java中Comparable和Comparator的区别

    Comparable

    比较者大于被比较者,返回正整数
    比较者等于被比较者,返回0
    比较者小于被比较者,返回负整数

    
    public class Domain implements Comparable<Domain>
    {
       private String str;
    
       public Domain(String str)
       {
           this.str = str;
       }
    
       public int compareTo(Domain domain)
       {
           if (this.str.compareTo(domain.str) > 0)
               return 1;
           else if (this.str.compareTo(domain.str) == 0)
               return 0;
           else 
               return -1;
       }
    
       public String getStr()
       {
           return str;
       }
    }
    
    public static void main(String[] args)
       {
           Domain d1 = new Domain("c");
           Domain d2 = new Domain("c");
           Domain d3 = new Domain("b");
           Domain d4 = new Domain("d");
           System.out.println(d1.compareTo(d2));
           System.out.println(d1.compareTo(d3));
           System.out.println(d1.compareTo(d4));
       }
    

    运行结果为:

    0
    1
    -1
    

    Comparator

    o1大于o2,返回正整数
    o1等于o2,返回0
    o1小于o3,返回负整数

    public class DomainComparator implements Comparator<Domain>
    {
       public int compare(Domain domain1, Domain domain2)
       {
           if (domain1.getStr().compareTo(domain2.getStr()) > 0)
               return 1;
           else if (domain1.getStr().compareTo(domain2.getStr()) == 0)
               return 0;
           else 
               return -1;
       }
    }
    
    public static void main(String[] args)
    {
       Domain d1 = new Domain("c");
       Domain d2 = new Domain("c");
       Domain d3 = new Domain("b");
       Domain d4 = new Domain("d");
       DomainComparator dc = new DomainComparator();
       System.out.println(dc.compare(d1, d2));
       System.out.println(dc.compare(d1, d3));
       System.out.println(dc.compare(d1, d4));
    }
    

    看一下运行结果:

    0
    1
    -1
    

    因为泛型指定死了,所以实现Comparator接口的实现类只能是两个相同的对象(不能一个Domain、一个String)进行比较了,实现Comparator接口的实现类一般都会以"待比较的实体类+Comparator"来命名

    总结

    如果实现类没有实现Comparable接口,又想对两个类进行比较(或者实现类实现了Comparable接口,但是对compareTo方法内的比较算法不满意),那么可以实现Comparator接口,自定义一个比较器,写比较算法。

    实现Comparable接口的方式比实现Comparator接口的耦合性要强一些,如果要修改比较算法,要修改Comparable接口的实现类,而实现Comparator的类是在外部进行比较的,不需要对实现类有任何修改。

    • 对于一些普通的数据类型(比如 String, Integer, Double…),它们默认实现了Comparable 接口,实现了 compareTo 方法,我们可以直接使用。
    • 而对于一些自定义类,它们可能在不同情况下需要实现不同的比较策略,我们可以新创建 Comparator 接口,然后使用特定的 Comparator 实现进行比较。

    文章转载自:
    Java8 - 使用 Comparator.comparing 进行排序
    对map集合排序

    相关文章

      网友评论

          本文标题:Java8 - 对集合排序

          本文链接:https://www.haomeiwen.com/subject/rlrlbktx.html