Java

Collection.sortのcompareのオーバーライドについて解説

Collection.sortがおまじない状態

現場でソースコードを読んでいるときに

Collection.sort

を使っている箇所について何をしているか理解できませんでした。。

【Java】Comparatorがおまじない状態です

っていう記事もあり、

みんな悩んでいるんだなぁ

ということで

私なりに理解したことをまとめました。

ソースコードの例

まずは読みやすい例から紹介します。

5つの数字を昇順ソートにするプログラムです。

昇順ソート

ソースコード

package brog;//自分の環境に合わせてください
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Arrays;
public class Sorttest1 {
    public static void main(String[] args) {
    	
    	List num_list = new ArrayList<>(Arrays.asList(30,55,20,15,40));
        
        Collections.sort(num_list);
        
        for (int i=0  ; i< num_list.size() ;i++ ) {
            System.out.println(num_list.get(i));
        }
    }
}

出力結果

  • 15
  • 20
  • 30
  • 40
  • 55

昇順ソートはわかりやすい

このソースコードはわかると思います。

9行目で宣言したリスト(num_list)を

10行目のCollections.sortに

引数として渡してあげると

昇順ソートしてくれるという理解です。

しかーし!

問題は降順ソートする場合です。

一気にわからなくなりました。。

以下、降順ソートのソースコードです

降順ソート

ソースコード

package brog;//自分の環境に合わせてください。
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Arrays;
public class SortTest2 {
    public static void main(String[] args) {
    	
    	List num_list = new ArrayList<>(Arrays.asList(30,55,20,15,40));
        
    	Collections.sort(num_list,new java.util.Comparator(){
            @Override
            public int compare(Integer i1,Integer i2) {
            	return i2 - i1;
            }
        });
        for (int i=0  ; i< num_list.size() ;i++ ) {
            System.out.println(num_list.get(i));
        }
    }
}

出力結果

  • 55
  • 40
  • 30
  • 20
  • 15

全然わからん!

・・・・ボン!

脳内が例外エラーになりました。

疑問がめっちゃわきます。

昇順ソートを降順ソートに変えただけなのに

コードが一気に増えた!

なんか一個インスタンス生成しているし。

疑問点

私が特にわからなかった点はこの3つでした。

  1. Comparatorってなに?
  2. Compareメソッドとは?
  3. Compareでなぜ引き算してるの?


私が理解した範囲で解説していきます。

1.Comparatorってなに?

まず降順ソートのソースコード11行目に登場する

Comparatorとはなんでしょう?

Oracle javaの公式サイト

には以下の記載がありました。

指定されたコンパレータが示す順序に従って、指定されたリストをソートします。リストのすべての要素は、指定されたコンパレータによって「相互に比較可能」でなければいけません。

つまり、Collection.Sortは

Comparator(コンパレータ)の指示に従ってソートしている

ということなのです。

昇順ソートは?

あれ?でも昇順ソートにコンパレータは渡されてないよ?(昇順ソートのソースコード9行目)

コンパレータに何も渡さない場合は何ソートになるのか、公式サイトにもはっきりとは書いていませんが、

『Comparatorの指示がなければ昇順ソート』

という理解で良いと思います

2.Compareメソッドとは?

そして2つの目の疑問

Compareメソッドとは何か?

その名の通り

Compare(比較)

を担当するメソッドです。

そもそもソートというのは、

マージソート
バブルソート
クイックソート

・・・と

様々なソートがありますが、

どんなソートの仕方であっても

『2つの値を比較して取り替える』

という処理が何回も繰り返されて、

ソートが行われます。

『2つの値を比較する処理』

を担当しているのが

Compareメソッド

なのです。

3.Compareでなぜ引き算してるの?

降順ソートのソースコード11~16行目で

compareメソッドにi1,i2という引数があり

それを引き算してreturnで返していますね。

降順ソートのソースコード11~16行目

Collections.sort(num_list,new java.util.Comparator(){
            @Override
            public int compare(Integer i1,Integer i2) {
            	return i2 - i1;
            }
        });

なんで引き算をしているの?

Comapreメソッドは

隣り合わせの2つの引数を比較した後、

正か負

で判定返す役割を担当しています。

これは仕様なので覚えてもらうしかないのですが

なぜ引き算しているかというと

Collection.sortの仕様として

Comapre2つの値(i1,i2)を渡し返ってきた値が

  • 正ならi1とi2を入れ替える
  • ゼロ以下なら何もしない

という仕様になっているからです。

なので、降順ソートにしたいので、

i2 - i1

としているわけです

要はなんなの?

色々解説してしまいましたが

あえて1つ言うならば

意識してもらいたいことは一つです

ソートはどんなソートであっても必ず『比較して入れ替える』処理が入っている

ということです。

なので

Compareメソッド(比較メソッド)をオーバーライドすることで

様々な順番に並び替えることが可能

だという事です。

どのようなソートができるか?

先ほど

Compareメソッド(比較メソッド)をオーバーライドすることで様々な順番に並び替えることが可能

といいましたが、

例えばどのようなソートができるのか?

というと、

偶数が昇順で先に表示され、そのあと奇数が昇順で表示される

といった順序も

降順ソートのCompareを箇所を以下のように書き換えるだけで実現ができます。

複雑なソート例

偶数が昇順で先に表示されそのあと奇数が昇順で表示されるソート
Compareの箇所のみ修正

Collections.sort(num_list,new java.util.Comparator(){
            @Override
            public int compare(Integer i1,Integer i2) {
            	 int result = i1%2 - i2%2;
                 if(result==0)
                 {
                   result = i1-i2;
                 }
                 return result;
            }

出力結果

  • 20
  • 30
  • 40
  • 15
  • 55

中級者への道

今回のCompareをオーバーライドしている箇所のようにわけのわからないプログラムソースに出会ったときに必要なのが

疑問を言語化して分解するです。

今回私は混乱してしまったので3つの疑問にわけました。

  1. Comparatorってなに?
  2. Compareメソッドとは?
  3. Compareでなぜ引き算してるの?

これを1つ1つ調べて理解していけば、最終的には理解できるようになります。

疑問を言語化して複数に分解する

広告




関連記事