読者です 読者をやめる 読者になる 読者になる

俺とプログラミング

某IT企業でエンジニアをしてます。このブログではプログラミングに関わることを幅広く発信します。

Javaで自作クラスをソートする3通りの方法【Java8】

Java

Javaで自前のクラスをソートするにはどうしたらよいか紹介します。Javaで配列やコレクションのソートを行うには主に3通りの方法があります。Java8以降ならばラムダ式がもっとも簡潔に書けます。それでは見ていきましょう。

1. ラムダ式を用いる方法(Java8以降):

自作クラスのPerson型を年齢順でソーティングします。

import java.util.ArrayList;

class Person{
  int age;
  String name;
  public Person( int a, String n ){ 
    age = a;
    name = n;
  }
  public  String toString(){
    return name + ":" + Integer.toString(age);
  }
}

class Main{
  public static void main(String[] av){
    ArrayList<Person> al = new ArrayList<Person>(){
        {
            add( new Person( 11, "katsuo" ) ); 
            add( new Person( 24, "sazae" ) ); 
            add( new Person( 9, "wakame" ) ); 
        }
    };
    al.sort((a,b)-> a.age - b.age ); /*ラムダ式*/
    System.out.println( al );
  }
}

実行結果

[wakame:9, katsuo:11, sazae:24]

ラムダ式で書くと非常に簡潔にソートの方式を指定できていることが分かります。ラムダ式は右辺が一行の場合、それが返り値となります。ここで注意しておきたいのは、返り値はboolean型ではなく、int型ということです。
逆順でソートしたかったときは以下のように書くだけです。簡単ですね。

al.sort( (a,b)-> b.age - a.age ); 

もし、年齢順ではなく、名前順でソートしたい時はどうすればよいでしょうか?
String型のメソッドcompareToをラムダ式内で呼び出します。

al.sort( (a,b)->a.name.compareTo( b.name )  );

実行結果

[katsuo:11, sazae:24, wakame:9]




2. Comparableインターフェースを実装する方法:

ComparableインターフェースのcompareToメソッドをオーバーライドして実装する方法です。

import java.util.ArrayList;
import java.util.Collections;

class Person implements Comparable<Person>{
  int age;
  String name;
  public Person( int a, String n ){ 
    age = a;
    name = n;
  }
  public  String toString(){
    return name + ":" + Integer.toString(age);
  }

  @Override
  public int compareTo( Person p ){
    return this.age - p.age;
  }
}

class Main{
  public static void main(String[] av){
    ArrayList<Person> al = new ArrayList<>();
    al.add( new Person( 11, "katsuo" ) ); 
    al.add( new Person( 24, "sazae" ) ); 
    al.add( new Person(  9, "wakame" ) ); 
    Collections.sort( al );
    System.out.println( al );
  }
}

実行結果

[wakame:9, katsuo:11, sazae:24]

Comparableインターフェースはjava.langパッケージに属しているので、importすることなく利用できます。compareToの返り値はラムダ式と同様にint型でなければなりません。ここで、Comparableに型名を指定しましょう。指定しない場合、compareToの引数にObject型をとらなければなりません。キャストの手間もあり、面倒です。
Java8以前はArrayListにsort関数が実装されていない点に注意です。



3. Comparatorを使う方法:

import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;

class Person{
  int age;
  String name;
  public Person( int a, String n ){ 
    age = a;
    name = n;
  }
  public  String toString(){
    return name + ":" + Integer.toString(age);
  }
}

class Main{
  public static void main(String[] av){
    ArrayList<Person> al = new ArrayList<>();
    al.add( new Person( 11, "katsuo" ) ); 
    al.add( new Person( 24, "sazae" ) ); 
    al.add( new Person(  9, "wakame" ) ); 
    Collections.sort( al, new Comparator<Person>(){
        @Override
        public int compare(Person a, Person b){
          return a.age - b.age;
        }
    });
    System.out.println( al );
  }
}

Comparator型を無名クラスで生成しています。ここでも、Comparatorに型指定をしておきましょう。実はラムダ式と内部的にやっていることは一緒ですが、コードが長くなってします。Java8以降であれば、ラムダ式で書いた方がコードの見通しもよくなると思います。



配列ではどうするか:

最後に配列でのソートについて、見ていきます。コレクションとほぼ同じです。

import java.util.Arrays;

class Person{
  int age;
  String name;
  public Person( int a, String n ){ 
    age = a;
    name = n;
  }
  public  String toString(){
    return name + "\t" + Integer.toString(age);
  }
}

class Main{
  public static void main(String[] av){
    Person[] arr = {new Person(11,"katsuo"), 
                    new Person(24, "sazae"), 
                    new Person(9,"wakame")};
    Arrays.sort( arr, (a,b)-> a.age - b.age ); 
    for ( Person p : arr ){
      System.out.println( p );
    }
  }
}

実行結果

wakame	9
katsuo	11
sazae	24

違いは以下の部分だけです

Arrays.sort( arr, (a,b)-> a.age - b.age ); 

ラムダ式以外の方法でもまったく変わりません。

Javaプログラマーなら習得しておきたい Java SE 8 実践プログラミング
Java 最強リファレンス
JavaFX & Java8プログラミング―Javaによる新しいGUIプログラミング入門

Copyright © 2016 ttlg All Rights Reserved.