List 中元素的排序

List 中的元素不一定都是 String, Number 这种类型的,遇到自定义的对象,需要按对象的某一个维度去排序,该如何做?这里用两种方式实现,但暂时不深究原理。个人较为推崇第二种方法,代码耦合少。

本文用到的代码存于:http://git.oschina.net/iridiumcao/iridiumonline/tree/master/hellojavase/src/main/java/info/iridiumcao/hellojavase/collection

法一 让被排序元素实现 Comparable 接口

简单地说,就是让需要排序的元素实现 Comparable 接口,元素加入到 List 后,直接调用 Collections.sort(Object) 方法即可。参考代码如下:

public class Person implements Comparable<Person> {
    private String name;
    private int age;
    private String email;
    public Person() {
    }
    public Person(String name, int age, String email) {
        this.name = name;
        this.age = age;
        this.email = email;
    }
    //... 此处省略 getter 和 setter 方法,以节省篇幅。
    @Override
    public String toString() {
        return this.name + ": " + age;
    }
    @Override
    public int compareTo(Person o) {
        return this.getAge() - o.getAge();
    }
}
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
public class Client {
    public static void main(String[] args) {
        Person p1 = new Person("Zhang San", 30, "zhangsan@hotmail.com");
        Person p2 = new Person("Li Si", 29, "lisi@gmail.com");
        Person p3 = new Person("Wang Wu", 100, "wangwu@yahoo.com");
        List<Person> list = new ArrayList<Person>();
        list.add(p1);
        list.add(p2);
        list.add(p3);
        for (Person p : list) {
            System.out.println(p);
        }
        Collections.sort(list);
        for (Person p : list) {
            System.out.println(p);
        }
    }
}

法二 单独实现 Comparator 接口

简单地说,这种方法不需要改变被排序元素的类,需要一个 Comparator 的实例,然后调用 Collections.sort(Object, Comparator) 方法。实际使用时,如果比较规则很简单,使用内部匿名类即可。这种方法可达到「非侵入式」(non-intrusive)。

public class Person {
    private String name;
    private int age;
    private String email;
    public Person() {
    }
    public Person(String name, int age, String email) {
        this.name = name;
        this.age = age;
        this.email = email;
    }
    //... 此处省略 getter 和 setter 方法,以节省篇幅。
    @Override
    public String toString() {
        return this.name + ": " + age;
    }
}
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
public class Client1 {
    public static void main(String[] args) {
        Person p1 = new Person("Zhang San", 30, "zhangsan@hotmail.com");
        Person p2 = new Person("Li Si", 29, "lisi@gmail.com");
        Person p3 = new Person("Wang Wu", 100, "wangwu@yahoo.com");
        List<Person> list = new ArrayList<Person>();
        list.add(p1);
        list.add(p2);
        list.add(p3);
        for (Person p : list) {
            System.out.println(p);
        }
        Collections.sort(list, new Comparator<Person>() {
            @Override
            public int compare(Person o1, Person o2) {
                return o1.getAge() - o2.getAge();
            }
        });
        for (Person p : list) {
            System.out.println(p);
        }
    }
}

Collections.sort 方法的第二个参数是一个匿名的 Comparator 子类,这个写法,很有些 FP(函数式编程) 的味道,不过这里传入的是类。这个 Client 类还可以用 Java 8的新语法改写为:

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
/**
 * 本例应用 Java 8 的 lambda 表达式以及 forEach 循环
 */
public class Client2 {
    public static void main(String[] args) {
        Person p1 = new Person("Zhang San", 30, "zhangsan@hotmail.com");
        Person p2 = new Person("Li Si", 29, "lisi@gmail.com");
        Person p3 = new Person("Wang Wu", 100, "wangwu@yahoo.com");
        List<Person> list = new ArrayList<>();
        list.add(p1);
        list.add(p2);
        list.add(p3);
        list.forEach(System.out::println);
        Collections.sort(list, (o1, o2) -> {
            return o1.getAge() - o2.getAge(); // 以年龄排序
        });
        list.forEach(System.out::println);
    }
}