Java8 - 对集合排序

2020-11-09  本文已影响0人  liuliuzo

对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的类是在外部进行比较的,不需要对实现类有任何修改。

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

上一篇 下一篇

猜你喜欢

热点阅读