java Collections.sort对List排序的两种方法

方法一:Comparable

方法一只需两个步骤

  1. 需要排序的类实现Comparable接口,在compareTo方法里定义排序规则
  2. 调用Collections.sort(List<T> list)方法排序

下面看下示例代码,首先创建一个Student类,实现Comparable接口

public static class Student implements Comparable<Student> {
	
	public String name;
	public int age;
	
	public Student(String name, int age) {
		this.name = name;
		this.age = age;
	}
	
	@Override
	public int compareTo(Student o) {
		int result = this.name.compareTo(o.name);
		if(result == 0) {
			result = Integer.compare(this.age, o.age);
		}
		return result;
	}

	@Override
	public String toString() {
        return "{name:" + name + ",age:" + age + "}";
    }
}

然后调用Collections.sort(List<T> list)方法排序

public static void main(String[] args) {
	List<Student> students = new ArrayList<Student>();
	Student student1 = new Student("CCC", 17);
	Student student2 = new Student("BBB", 19);
	Student student3 = new Student("BBB", 18);
	Student student4 = new Student("AAA", 18);
	students.add(student1);
	students.add(student2);
	students.add(student3);
	students.add(student4);
	System.out.println("排序前:" + students);
	Collections.sort(students);
	System.out.println("排序后:" + students);
}

测试结果如下,可以看到先根据name升序排序,若name相同再根据age升序排序

排序前:[{name:CCC,age:17}, {name:BBB,age:19}, {name:BBB,age:18}, {name:AAA,age:18}]
排序后:[{name:AAA,age:18}, {name:BBB,age:18}, {name:BBB,age:19}, {name:CCC,age:17}]

方法二:Comparator

方法二也只需两个步骤

  1. 创建一个排序类,实现Comparator接口,在compare方法里定义排序规则
  2. 调用Collections.sort(List<T> list, Comparator<? super T> c)方法排序

下面看下示例代码,首先创建一个Student类,这里的Student类不必再实现Comparable接口

public static class Student {
	
	public String name;
	public int age;
	
	public Student(String name, int age) {
		this.name = name;
		this.age = age;
	}

	@Override
	public String toString() {
        return "{name:" + name + ",age:" + age + "}";
    }
}

然后实现一个排序类SortByNameAge,在compare方法中定义排序规则

public static class SortByNameAge implements Comparator<Student> {
	@Override
	public int compare(Student o1, Student o2) {
		int result = o1.name.compareTo(o2.name);
		if(result == 0) {
			result = Integer.compare(o1.age, o2.age);
		}
		return result;
	}	
}

最后调用Collections.sort(List<T> list, Comparator<? super T> c)方法排序

public static void main(String[] args) {
	List<Student> students = new ArrayList<Student>();
	Student student1 = new Student("CCC", 17);
	Student student2 = new Student("BBB", 19);
	Student student3 = new Student("BBB", 18);
	Student student4 = new Student("AAA", 18);
	students.add(student1);
	students.add(student2);
	students.add(student3);
	students.add(student4);
	System.out.println("排序前:" + students);
	Collections.sort(students, new SortByNameAge());
	System.out.println("排序后:" + students);
}

输出结果如下,与方法一的结果一致,先根据name升序排序,若name相同再根据age升序排序

排序前:[{name:CCC,age:17}, {name:BBB,age:19}, {name:BBB,age:18}, {name:AAA,age:18}]
排序后:[{name:AAA,age:18}, {name:BBB,age:18}, {name:BBB,age:19}, {name:CCC,age:17}]

Comparator相比Comparable的优点是不必修改原有的需要排序的类,特别适用于需排序的类在第三方jar包中无法对其源码进行修改的情况。

Comparator还有一个优点是我们可以同时实现多个排序方案,在需要的时候选择合适的方案进行排序,比如我们可以实现一个SortByAgeName的排序类,先对Age进行排序,若age相等,再对name排序

public static class SortByAgeName implements Comparator<Student> {
	@Override
	public int compare(Student o1, Student o2) {
		int result = Integer.compare(o1.age, o2.age);
		if(result == 0) {
			result = o1.name.compareTo(o2.name);
		}
		return result;
	}	
}

然后修改Collections.sort,第二个参数传新的排序类

Collections.sort(students, new SortByAgeName());

输出结果如下,先对Age进行升序排序,若age相等,再对name升序排序

排序前:[{name:CCC,age:17}, {name:BBB,age:19}, {name:BBB,age:18}, {name:AAA,age:18}]
排序后:[{name:CCC,age:17}, {name:AAA,age:18}, {name:BBB,age:18}, {name:BBB,age:19}]

源码解析

我们先分别看下Collections.sort(List<T> list)和Collections.sort(List<T> list, Comparator<? super T> c)这两个方法的源码

Collections.sort(List<T> list)源码

/**
 * Sorts the specified list into ascending order, according to the
 * {@linkplain Comparable natural ordering} of its elements.
 * All elements in the list must implement the {@link Comparable}
 * interface.  Furthermore, all elements in the list must be
 * <i>mutually comparable</i> (that is, {@code e1.compareTo(e2)}
 * must not throw a {@code ClassCastException} for any elements
 * {@code e1} and {@code e2} in the list).
 *
 * <p>This sort is guaranteed to be <i>stable</i>:  equal elements will
 * not be reordered as a result of the sort.
 *
 * <p>The specified list must be modifiable, but need not be resizable.
 *
 * @implNote
 * This implementation defers to the {@link List#sort(Comparator)}
 * method using the specified list and a {@code null} comparator.
 *
 * @param  <T> the class of the objects in the list
 * @param  list the list to be sorted.
 * @throws ClassCastException if the list contains elements that are not
 *         <i>mutually comparable</i> (for example, strings and integers).
 * @throws UnsupportedOperationException if the specified list's
 *         list-iterator does not support the {@code set} operation.
 * @throws IllegalArgumentException (optional) if the implementation
 *         detects that the natural ordering of the list elements is
 *         found to violate the {@link Comparable} contract
 * @see List#sort(Comparator)
 */
@SuppressWarnings("unchecked")
public static <T extends Comparable<? super T>> void sort(List<T> list) {
    list.sort(null);
}

Collections.sort(List<T> list, Comparator<? super T> c)源码

/**
 * Sorts the specified list according to the order induced by the
 * specified comparator.  All elements in the list must be <i>mutually
 * comparable</i> using the specified comparator (that is,
 * {@code c.compare(e1, e2)} must not throw a {@code ClassCastException}
 * for any elements {@code e1} and {@code e2} in the list).
 *
 * <p>This sort is guaranteed to be <i>stable</i>:  equal elements will
 * not be reordered as a result of the sort.
 *
 * <p>The specified list must be modifiable, but need not be resizable.
 *
 * @implNote
 * This implementation defers to the {@link List#sort(Comparator)}
 * method using the specified list and comparator.
 *
 * @param  <T> the class of the objects in the list
 * @param  list the list to be sorted.
 * @param  c the comparator to determine the order of the list.  A
 *        {@code null} value indicates that the elements' <i>natural
 *        ordering</i> should be used.
 * @throws ClassCastException if the list contains elements that are not
 *         <i>mutually comparable</i> using the specified comparator.
 * @throws UnsupportedOperationException if the specified list's
 *         list-iterator does not support the {@code set} operation.
 * @throws IllegalArgumentException (optional) if the comparator is
 *         found to violate the {@link Comparator} contract
 * @see List#sort(Comparator)
 */
@SuppressWarnings({"unchecked", "rawtypes"})
public static <T> void sort(List<T> list, Comparator<? super T> c) {
    list.sort(c);
}

可以看到这两个方法内部其实都是调用了list.sort(Comparator<? super E> c)方法,只是其中一个参数传空

所以上面介绍的方法一和方法二和下面的代码是等价的

public static void main(String[] args) {
	List<Student> students = new ArrayList<Student>();
	Student student1 = new Student("CCC", 17);
	Student student2 = new Student("BBB", 19);
	Student student3 = new Student("BBB", 18);
	Student student4 = new Student("AAA", 18);
	students.add(student1);
	students.add(student2);
	students.add(student3);
	students.add(student4);
	System.out.println("排序前:" + students);
	students.sort(null);
	System.out.println("方法一排序后:" + students);
	students.sort(new SortByAgeName());
	System.out.println("方法二排序后:" + students);
}

测试结果如下

排序前:[{name:CCC,age:17}, {name:BBB,age:19}, {name:BBB,age:18}, {name:AAA,age:18}]
方法一排序后:[{name:AAA,age:18}, {name:BBB,age:18}, {name:BBB,age:19}, {name:CCC,age:17}]
方法二排序后:[{name:CCC,age:17}, {name:AAA,age:18}, {name:BBB,age:18}, {name:BBB,age:19}]

我们再深入看下List类中sort(Comparator<? super E> c)方法的源码

/**
 * Sorts this list according to the order induced by the specified
 * {@link Comparator}.
 *
 * <p>All elements in this list must be <i>mutually comparable</i> using the
 * specified comparator (that is, {@code c.compare(e1, e2)} must not throw
 * a {@code ClassCastException} for any elements {@code e1} and {@code e2}
 * in the list).
 *
 * <p>If the specified comparator is {@code null} then all elements in this
 * list must implement the {@link Comparable} interface and the elements'
 * {@linkplain Comparable natural ordering} should be used.
 *
 * <p>This list must be modifiable, but need not be resizable.
 *
 * @implSpec
 * The default implementation obtains an array containing all elements in
 * this list, sorts the array, and iterates over this list resetting each
 * element from the corresponding position in the array. (This avoids the
 * n<sup>2</sup> log(n) performance that would result from attempting
 * to sort a linked list in place.)
 *
 * @implNote
 * This implementation is a stable, adaptive, iterative mergesort that
 * requires far fewer than n lg(n) comparisons when the input array is
 * partially sorted, while offering the performance of a traditional
 * mergesort when the input array is randomly ordered.  If the input array
 * is nearly sorted, the implementation requires approximately n
 * comparisons.  Temporary storage requirements vary from a small constant
 * for nearly sorted input arrays to n/2 object references for randomly
 * ordered input arrays.
 *
 * <p>The implementation takes equal advantage of ascending and
 * descending order in its input array, and can take advantage of
 * ascending and descending order in different parts of the same
 * input array.  It is well-suited to merging two or more sorted arrays:
 * simply concatenate the arrays and sort the resulting array.
 *
 * <p>The implementation was adapted from Tim Peters's list sort for Python
 * (<a href="http://svn.python.org/projects/python/trunk/Objects/listsort.txt">
 * TimSort</a>).  It uses techniques from Peter McIlroy's "Optimistic
 * Sorting and Information Theoretic Complexity", in Proceedings of the
 * Fourth Annual ACM-SIAM Symposium on Discrete Algorithms, pp 467-474,
 * January 1993.
 *
 * @param c the {@code Comparator} used to compare list elements.
 *          A {@code null} value indicates that the elements'
 *          {@linkplain Comparable natural ordering} should be used
 * @throws ClassCastException if the list contains elements that are not
 *         <i>mutually comparable</i> using the specified comparator
 * @throws UnsupportedOperationException if the list's list-iterator does
 *         not support the {@code set} operation
 * @throws IllegalArgumentException
 *         (<a href="Collection.html#optional-restrictions">optional</a>)
 *         if the comparator is found to violate the {@link Comparator}
 *         contract
 * @since 1.8
 */
@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<? super E> c)内部其实是通过调用toArray()先把List转成数组,然后Arrays.sort()方法对数组进行排序,然后将排序完的数组结果设置回原来的List

总结

  • 实现Comparable需修改原实体类,若该类在jar包中无法修改则不适用
  • 实现Comparator无需修改原实体类,且可以提供多种排序实现
  • Collections.sort方法内部其实是调用List.sort方法,而List.sort方法内部其实是调用Arrays.sort方法实现排序

 

 

 

posted @ 2019-08-12 16:06  野猿新一  阅读(120)  评论(0编辑  收藏  举报