利用Java8按照元素对象的多字段对List进行排序
实例对象
public class WarningRule implements Serializable {
private String hour;
private String content;
//类型排序字段
private Integer order;
public WarningRule() {
}
public WarningRule(String hour, Integer order,String content ) {
this.hour = hour;
this.content = content;
this.order = order;
}
public String getHour() {
return hour;
}
public void setHour(String hour) {
this.hour = hour;
}
public String getContent() {
return content;
}
public void setContent(String content) {
this.content = content;
}
public Integer getOrder() {
return order;
}
public void setOrder(Integer order) {
this.order = order;
}
}
按照hour和order对List<WarningRule>进行排序,hour相同的时候按照order进行排序
Comparator<WarningRule> bya = Comparator.comparing(WarningRule::getHour).reversed();//按照a升序
Comparator<WarningRule> byb = Comparator.comparing(WarningRule::getOrder);//按照b升序
Collections.sort(warningRules,bya.thenComparing(byb));
看一下其中Comparator的源码:
@FunctionalInterface
public interface Comparator<T> {
int compare(T o1, T o2);
...
default Comparator<T> thenComparing(Comparator<? super T> other) {
Objects.requireNonNull(other);
return (Comparator<T> & Serializable) (c1, c2) -> {
int res = compare(c1, c2);
return (res != 0) ? res : other.compare(c1, c2);
};
}
...
public static <T, U extends Comparable<? super U>> Comparator<T> comparing(
Function<? super T, ? extends U> keyExtractor)
{
Objects.requireNonNull(keyExtractor);
return (Comparator<T> & Serializable)
(c1, c2) -> keyExtractor.apply(c1).compareTo(keyExtractor.apply(c2));
}
...
}
上面只列出了部分代码,可以看出其是一个函数式接口
Comparator<WarningRule> bya = Comparator.comparing(WarningRule::getHour);
我们看一下comparing方法
从上面的源码可以看出这个函数是默认函数,接收的参数是一个函数式接口,即可以传入像例子中的(WarningRule::getHour)类型的方法引用。apply方法接受一个参数返回一个值,即像例子中接收一个WarningRule对象返回其中的hour属性值
返回一个Comparator类型的函数
其返回的Comparator类型的对象利用了lambda表达式,因为Comparator是一个函数式接口,要实现其
int compare(T o1, T o2);
public static <T, U extends Comparable<? super U>> Comparator<T> comparing(
Function<? super T, ? extends U> keyExtractor)
{
Objects.requireNonNull(keyExtractor);
return (Comparator<T> & Serializable)
(c1, c2) -> keyExtractor.apply(c1).compareTo(keyExtractor.apply(c2));
}
return的是Comparator类型的对象,(c1, c2) -> keyExtractor.apply(c1).compareTo(keyExtractor.apply(c2));相当于是Comparator接口的匿名内部类,lambda表达式接收两个参数返回一个int类型的数,就是实现了int compare(T o1, T o2);方法。
而Collections.sort(warningRules,bya.thenComparing(byb));
排序则利用了Comparator的compare方法,看jdk的TimSort类的源码
private static <T> void binarySort(T[] a, int lo, int hi, int start,
Comparator<? super T> c) {
assert lo <= start && start <= hi;
if (start == lo)
start++;
for ( ; start < hi; start++) {
T pivot = a[start];
// Set left (and right) to the index where a[start] (pivot) belongs
int left = lo;
int right = start;
assert left <= right;
/*
* Invariants:
* pivot >= all in [lo, left).
* pivot < all in [right, start).
*/
while (left < right) {
int mid = (left + right) >>> 1;
//利用Comparator的compare方法
if (c.compare(pivot, a[mid]) < 0)
right = mid;
else
left = mid + 1;
}
assert left == right;
/*
* The invariants still hold: pivot >= all in [lo, left) and
* pivot < all in [left, start), so pivot belongs at left. Note
* that if there are elements equal to pivot, left points to the
* first slot after them -- that's why this sort is stable.
* Slide elements over to make room for pivot.
*/
int n = start - left; // The number of elements to move
// Switch is just an optimization for arraycopy in default case
switch (n) {
case 2: a[left + 2] = a[left + 1];
case 1: a[left + 1] = a[left];
break;
default: System.arraycopy(a, left, a, left + 1, n);
}
a[left] = pivot;
}
}
可以看出排序利用了我们需要实现的Comparator接口的compare方法。
在我们上面所述的实例中compare方法的参数传入的是两个WarningRule类型的对象,
调用compare方法,而compare方法就是(c1, c2) -> keyExtractor.apply(c1).compareTo(keyExtractor.apply(c2)),
其中的keyExtractor就是WarningRule::getHour。
接下来看thenComparing方法:
bya.thenComparing(byb)
default Comparator<T> thenComparing(Comparator<? super T> other) {
Objects.requireNonNull(other);
return (Comparator<T> & Serializable) (c1, c2) -> {
int res = compare(c1, c2);
return (res != 0) ? res : other.compare(c1, c2);
};
}
这个方法接收一个Comparator类型的参数,它先调用自身的compare进行比较,如果返回0说明当前两个对象的这个属性值相等,则调用other的compare 去比较other这个Comparator当时实现compare时传入给compare做参数的对象的属性值
即byb 参数WarningRule的属性值order
如想对对象的一些属性进行降序,例如对hour进行降序,值相同时对order进行升序,可以
Comparator<WarningRule> bya = Comparator.comparing(WarningRule::getHour).reversed();//按照a降序
Comparator<WarningRule> byb = Comparator.comparing(WarningRule::getOrder);//按照b升序
看一下reversed()的源码:
default Comparator<T> reversed() {
return Collections.reverseOrder(this);
}
继续往下:
public static <T> Comparator<T> reverseOrder(Comparator<T> cmp) {
if (cmp == null)
return reverseOrder();
if (cmp instanceof ReverseComparator2)
return ((ReverseComparator2<T>)cmp).cmp;
return new ReverseComparator2<>(cmp);
}
继续:
ReverseComparator2(Comparator<T> cmp) {
assert cmp != null;
this.cmp = cmp;
}
public int compare(T t1, T t2) {
return cmp.compare(t2, t1);
}
可以看到将Comparator转化为ReverseCpmparator2,是Collections的内部类。
private static class ReverseComparator2<T> implements Comparator<T>,
Serializable
{
private static final long serialVersionUID = 4374092139857L;
/**
* The comparator specified in the static factory. This will never
* be null, as the static factory returns a ReverseComparator
* instance if its argument is null.
*
* @serial
*/
final Comparator<T> cmp;
ReverseComparator2(Comparator<T> cmp) {
assert cmp != null;
this.cmp = cmp;
}
public int compare(T t1, T t2) {
return cmp.compare(t2, t1);
}
public boolean equals(Object o) {
return (o == this) ||
(o instanceof ReverseComparator2 &&
cmp.equals(((ReverseComparator2)o).cmp));
}
public int hashCode() {
return cmp.hashCode() ^ Integer.MIN_VALUE;
}
@Override
public Comparator<T> reversed() {
return cmp;
}
}
看其中的compare方法:
public int compare(T t1, T t2) {
return cmp.compare(t2, t1);
}
比t1和t2的值进行交换,以达到逆序效果。