Comparator詳解

Comparator是一個(gè)專用的比較器,當(dāng)這個(gè)對(duì)象不支持自比較或者自比較函數(shù)不能滿足要求時(shí)惕味,可寫一個(gè)比較器來完成兩個(gè)對(duì)象之間大小的比較。Comparator體現(xiàn)了一種策略模式(strategy design pattern),就是不改變對(duì)象自身,而用一個(gè)策略對(duì)象(strategy object)來改變它的行為胖眷。

比如我有一組數(shù)字需要對(duì)其進(jìn)行正序排序,java8之前我們通常的做法是:

 Integer [] values = new Integer[]{1,0,3,5,7,8,5,4,3,7,9,56,3,23};
Arrays.sort(values, new Comparator<Integer>() {
            @Override
            public int compare(Integer value1, Integer value2) {
                return value1- value2;
            }
        });

而在java8中,由于新增lambda表達(dá)式,我們可以很簡(jiǎn)潔的使用如下的方式:

Integer [] values = new Integer[]{1,0,3,5,7,8,5,4,3,7,9,56,3,23};
 Arrays.sort(values, (x,y) -> x-y);

可以看到代碼量更加簡(jiǎn)潔更加清晰,jdk甚至為了排序做了一些定制的方法,比如上面的代碼可以寫成如下的方式,更加讓人容易理解:

Integer [] values = new Integer[]{1,0,3,5,7,8,5,4,3,7,9,56,3,23};
Arrays.sort(values, Comparator.comparingInt(x -> x));

由于本文不會(huì)專門講解java8中關(guān)于lambda表達(dá)式的內(nèi)容,只講解主題相關(guān)的Comparator的使用,如果想了解更多關(guān)于lambda表達(dá)式的內(nèi)容,還請(qǐng)參考其他文章.

Comparator使用

Comparator是一個(gè)函數(shù)式接口,只有一個(gè) int compare(T o1, T o2);方法供外部使用,但是java8在其基礎(chǔ)上定制了許多default方法,這些default方法,開箱即用,下面我們就看看有哪些default方法以及如何使用.

reversed()

default Comparator<T> reversed() {
        return Collections.reverseOrder(this);
    }

顧名思義,可以知道這個(gè)方法是用來生成一個(gè)逆序器,比如我們開始需要得到一個(gè)正序的排序序列,然后又想得到一個(gè)反轉(zhuǎn)的排序序列,就可以使用該方法,比如:

Integer [] values = new Integer[]{1,0,3,5,7,8,5,4,3,7,9,56,3,23};
Comparator<Integer> comparator = Comparator.comparingInt(x -> x);
Arrays.sort(values, comparator);
System.out.println(JSON.toJSONString(values));
Arrays.sort(values, comparator.reversed());
System.out.println(JSON.toJSONString(values));

結(jié)果如下:

[0,1,3,3,3,4,5,5,7,7,8,9,23,56]
[56,23,9,8,7,7,5,5,4,3,3,3,1,0]

可以看到,先得到正序排序的序列,然后調(diào)用comparator.reversed(),我們將內(nèi)容進(jìn)行反轉(zhuǎn)

thenComparing(Comparator<? super T> other)

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);
        };
    }

顧名思義,該方法是在原有的比較器上再加入一個(gè)比較器,比如我們有一些用戶,在對(duì)其進(jìn)行排序的時(shí)候,我們首先對(duì)他的名字長度進(jìn)行排序,然后再對(duì)他的年齡進(jìn)行排序,如下:

person類

class Person{
        private int age;
        private String name;
        public int getAge() {
            return age;
        }
        public void setAge(int age) {
            this.age = age;
        }
        public String getName() {
            return name;
        }
        public void setName(String name) {
            this.name = name;
        }
        public Person(int age, String name) {
            this.age = age;
            this.name = name;
        }
        @Override
        public String toString() {
            return "Person{" +
                    "age=" + age +
                    ", name='" + name + '\'' +
                    '}';
        }
    }

測(cè)試代碼:

Person [] persons = new Person[]{
                new Person(22,"zhangsan"),
                new Person(23,"lisi"),
                new Person(23,"wangwu"),
                new Person(22,"wangwu"),
                new Person(22,"lisi"),
                new Person(23,"zhangsan")
        };
        System.out.println(JSON.toJSONString(persons));
        Comparator<Person> comparator = Comparator.comparingInt(x -> x.name.length());
        Arrays.sort(persons,comparator);
        System.out.println(JSON.toJSONString(persons));
        comparator = comparator.thenComparing(Comparator.comparingInt(x->x.age));
        Arrays.sort(persons,comparator);
        System.out.println(JSON.toJSONString(persons));

結(jié)果如下:

[{"age":22,"name":"zhangsan"},{"age":23,"name":"lisi"},{"age":23,"name":"wangwu"},{"age":22,"name":"wangwu"},{"age":22,"name":"lisi"},{"age":23,"name":"zhangsan"}]
[{"age":23,"name":"lisi"},{"age":22,"name":"lisi"},{"age":23,"name":"wangwu"},{"age":22,"name":"wangwu"},{"age":22,"name":"zhangsan"},{"age":23,"name":"zhangsan"}]
[{"age":22,"name":"lisi"},{"age":23,"name":"lisi"},{"age":22,"name":"wangwu"},{"age":23,"name":"wangwu"},{"age":22,"name":"zhangsan"},{"age":23,"name":"zhangsan"}]

上述代碼甚至可以簡(jiǎn)化成如下:

Comparator<Person> comparator = Comparator.comparing(Person::getName).thenComparing(Person::getAge);

default <U> Comparator<T> thenComparing(
Function<? super T, ? extends U> keyExtractor,
Comparator<? super U> keyComparator)

default <U> Comparator<T> thenComparing(
            Function<? super T, ? extends U> keyExtractor,
            Comparator<? super U> keyComparator)
    {
        return thenComparing(comparing(keyExtractor, keyComparator));
    }

待補(bǔ)充

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市霹崎,隨后出現(xiàn)的幾起案子珊搀,更是在濱河造成了極大的恐慌,老刑警劉巖仿畸,帶你破解...
    沈念sama閱讀 211,123評(píng)論 6 490
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異朗和,居然都是意外死亡错沽,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,031評(píng)論 2 384
  • 文/潘曉璐 我一進(jìn)店門眶拉,熙熙樓的掌柜王于貴愁眉苦臉地迎上來千埃,“玉大人,你說我怎么就攤上這事忆植》趴桑” “怎么了?”我有些...
    開封第一講書人閱讀 156,723評(píng)論 0 345
  • 文/不壞的土叔 我叫張陵朝刊,是天一觀的道長耀里。 經(jīng)常有香客問我,道長拾氓,這世上最難降的妖魔是什么冯挎? 我笑而不...
    開封第一講書人閱讀 56,357評(píng)論 1 283
  • 正文 為了忘掉前任,我火速辦了婚禮咙鞍,結(jié)果婚禮上房官,老公的妹妹穿的比我還像新娘。我一直安慰自己续滋,他們只是感情好翰守,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,412評(píng)論 5 384
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著疲酌,像睡著了一般蜡峰。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 49,760評(píng)論 1 289
  • 那天事示,我揣著相機(jī)與錄音早像,去河邊找鬼。 笑死肖爵,一個(gè)胖子當(dāng)著我的面吹牛卢鹦,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播劝堪,決...
    沈念sama閱讀 38,904評(píng)論 3 405
  • 文/蒼蘭香墨 我猛地睜開眼冀自,長吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來了秒啦?” 一聲冷哼從身側(cè)響起熬粗,我...
    開封第一講書人閱讀 37,672評(píng)論 0 266
  • 序言:老撾萬榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎余境,沒想到半個(gè)月后驻呐,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 44,118評(píng)論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡芳来,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,456評(píng)論 2 325
  • 正文 我和宋清朗相戀三年含末,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片即舌。...
    茶點(diǎn)故事閱讀 38,599評(píng)論 1 340
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡佣盒,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出顽聂,到底是詐尸還是另有隱情肥惭,我是刑警寧澤,帶...
    沈念sama閱讀 34,264評(píng)論 4 328
  • 正文 年R本政府宣布紊搪,位于F島的核電站蜜葱,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏耀石。R本人自食惡果不足惜笼沥,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,857評(píng)論 3 312
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望娶牌。 院中可真熱鬧奔浅,春花似錦、人聲如沸诗良。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,731評(píng)論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽鉴裹。三九已至舞骆,卻和暖如春钥弯,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背督禽。 一陣腳步聲響...
    開封第一講書人閱讀 31,956評(píng)論 1 264
  • 我被黑心中介騙來泰國打工脆霎, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人狈惫。 一個(gè)月前我還...
    沈念sama閱讀 46,286評(píng)論 2 360
  • 正文 我出身青樓睛蛛,卻偏偏與公主長得像,于是被迫代替她去往敵國和親胧谈。 傳聞我的和親對(duì)象是個(gè)殘疾皇子忆肾,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,465評(píng)論 2 348

推薦閱讀更多精彩內(nèi)容