sort()排序(Comparable、Comparator)

在收集对象之后,对对象进行排序是常用的动作。不用亲自操作排序算法Java.util. Collections提供有sort()方法。由于必须有索引才能进行排序,因此 Collections的sort()方法接受List操作对象。例如:

package coll_map;

import java.util.*;

public class SortDemo {
    public static void main(String[] args) {
        List nums=Arrays.asList(3,6,2,7,5,9,0);
        Collections.sort(nums);
        System.out.println(nums);
    }
}

这里写图片描述
1.操作 Comparable

package coll_map;

import java.util.*;

class Sort2 {
    private String name;
    private String ID;
    private int balance;

    Sort2(String name, String ID, int balance) {
        this.name = name;
        this.balance = balance;
        this.ID = ID;
    }

    @Override
    public String toString() {
        return String.format("账户(%s,%s,%d)", name,ID,balance);
    }
}
    public class Account{
        public static void main(String[] args) {
            List accounts=Arrays.asList(
                    new Sort2("zhangsan","9958X",999),
                    new Sort2("lisi","8779g",577),
                    new Sort2("wanger","99098X",6988)
                    );
            Collections.sort(accounts);
            System.out.println(accounts);
        }
    }

抛错: java.lang.ClassCastException
是因为Collections的sort方法,不知道是根据 Account的name、ID或 balance进行排序。sort()方法要求被排序的对象必须操作java.lang. Comparable接口,这个接口有个 compareto()方法必须返回大于0、等于0或小于0的数:

package coll_map;

import java.util.*;

class Sort2 implements Comparable<Sort2>{
    private String name;
    private String ID;
    private int balance;

    Sort2(String name, String ID, int balance) {
        this.name = name;
        this.balance = balance;
        this.ID = ID;
    }

    @Override
    public String toString() {
        return String.format("账户(%s,%s,%d)", name,ID,balance);
    }

    @Override
    public int compareTo(Sort2 o) {
        // TODO 自动生成的方法存根
        return this.balance-o.balance;//判断排序条件
    }
}
    public class Account{
        public static void main(String[] args) {
            List accounts=Arrays.asList(
                    new Sort2("zhangsan","9958X",999),
                    new Sort2("lisi","8779g",577),
                    new Sort2("wanger","99098X",6988)
                    );
            Collections.sort(accounts);
            System.out.println(accounts);
        }
    }

这里写图片描述

collections的sot()方法在取得a对象与b对象进行比较时,会先将a对象扮演(Cast)为 comparable(也因此若对象没操作 Comparable,将会抛出 Classcastexception),然后调用 a.compareto(b),如果a对象顺序上小于b对象则返回小于0的值,若顺序上相等则返回0,若顺序上a大于b则返回大于0的值。因此,上面的范例,将会依余额从小到大排列账户对象。前面的Sort类中,可以直接对 Integer进行排序,因为Integer就有操作 Comparable接口。
2.操作Comparator
String有操作Comparable:

package coll_map;

import java.util.*;

public class SortDemo {
    public static void main(String[] args) {
        List words=Arrays.asList("D","A","H","Y","E");
        Collections.sort(words);
        //如果只想用String的compareTo方法可以:words.sort(String::compareTo);
        System.out.println(words);
    }
}

这里写图片描述
但是如果有对象无法操作Comparable、拿不到原始码或者不能修改原始码。
比如让String排序结果反过来,就算修改String. Java后重新编译为 String.clas放回 rt jar中,也只有这个的JRE可以用,这已经不是标准API了。继承 string后再重新定义 compareto()也不可能,因为 String声明为 final,不能被继承。 Collections的sort()方法有另一个重载版本,可接受 Java util. Comparator接口的操作对象,如果使用这个版本,排序方式将根据 Comparator的 compare()定义来决定。例如:

package coll_map;
import java.util.*;

public class SortDemo {
    public static void main(String[] args) {
        List<String> words=Arrays.asList("D","A","H","Y","E");
        Collections.sort(words,new StringSort());
        System.out.println(words);
    }
}
class StringSort implements Comparator<String>{

    @Override
    public int compare(String o1, String o2) {
        // TODO 自动生成的方法存根
        return -o1.compareTo(o2);
    }
}

Comparator的 compare()会传入两个对象,如果o1顺序上小于o2则返回小于0的值,顺序相等则返回0,顺序上o1大于o2则返回大于0的值。在这个范例中,由于 string本身就是 Comparable,所以将 compareto()返回的值乘上-1,就可以调换排列顺序。

package coll_map;

import java.util.*;

public class SortDemo {
    public static void main(String[] args) {
        List<String> words=Arrays.asList("D","A","H","Y","E");
        //Collections.sort(words,(o1,o2) ->-o1.compareTo(o2));利用Lambda语法
        words.sort((o1,o2) ->-o1.compareTo(o2));//更简单利用Lambda语法
        System.out.println(words);
    }
}

在Java的规范中,与顺序有关的行为,通常要不对象本身是 Comparable,要不就是另行指定 Comparator对象告知如何排序。
例如,如果想针对数组进行排序,可以使用java.util.Arrays的sort()方法,如果查询API文件,会发现该方法针对对象排序时有两个版本:一个版本是你收集在数组中的对象必须是 Comparable()否则会抛出Classcastexception
,另一个版本则可以传入 compa rato指定排序方式.
Set的操作类之一java. util. TreeSet不仅拥有收集不重复对象的能力,还可用红黑树方式排序收集的对象,条件就是收集的对象必须是 comparable(否则会抛出 Classcastexception)或者是在创建TreeSet时指定 Comparator
对象。
Queue的操作类之一
java util. Priorityqueue也是,收集至 Priorityqueue的对象,会根据你指定的优先权来决定对象在队列中的序,优先权的告知,要不就是对象必须是 comparable(否则会抛出Classcastexception)或者是创建Priorityqueue时指定Comparator对象。
如果有个List中某些索引处包括null,现在让null排在最前头,之后依字符串的长度由大到小排序,这样重新定义compare:

    @Override
    public int compare(String o1, String o2) {
        if(o1==o2) {
            return 0;
        }
        if(o1==null) {
            return -1;
        }
        if(o2==null) {
            return 1;
        }
        if(o1.length()==o2.length()) {
            return 0;
        }
        if(o1.length()>o2.length()) {
            return -1;
        }
        return 1;
    }

当然其实可以利用高级语义API:

package coll_map;
import java.util.*;
import static java.util.Comparator.*;

public class SortDemo {
    public static void main(String[] args) {
        List<String> words=Arrays.asList("D","A","H","Y","E");
        words.sort(nullsFirst(reverseOrder));//高级语义
        System.out.println(words);
    }
}

reverseOrder()返回的 Comparator会是 Comparable对象上定义顺序的反序, nullsFirst接受 Comparator,在其定义的顺序上加上让null排在最前面的规则。
可以看到 import static适当的运用,可以让程序码表达出本身操作的意图相比以下程序代码来说清楚许多:

words.sort(Comparator.nullsFirst(Comparator.reverseOrder));

Conparator上还有很多方法可以使用,例如 comparing与 thenComparing等方法,要运用这些方法,得了解更多JDK8的 Lambda特性,例如位于java.util.function套件中的 Function等接口的意义

猜你喜欢

转载自blog.csdn.net/zkd758/article/details/80068405