ラムダ式と匿名クラス
配列の整列
インタフェースを実装したクラスを引数に取るメソッドがあります。
例えば、配列を整列する場合、sortというメソッドが使用できます。
Integer[] nums = {5,8,9,4,7};
// 整列
Arrays.sort(nums);
for(int n : nums) {
System.out.println(n);
}
ただし、通常は昇順にしかなりません。 これを他の順番で整列するには、第二引数を指定する必要があります。第二引数はインタフェースComparatorを実装したクラスのインスタンスを渡します。
Arrays.sort(nums, Comparatorを実装したクラスをnewしたもの );
Comparatorインタフェースでは compareというメソッドがありますので、Comparatorインタフェースを実装したクラスは必ず compareメソッドを作らなくてはなりません。compareメソッドは引数が2つのメソッドでこれを比較して結果(どちらが先か)を返します。
Arrays.sort内では、渡されてきたインスタンスのcompareメソッドを呼び出して2つの要素の比較を行います。内部では、compareメソッドを何回も呼び出して全要素を比較し、整列を行うわけです。
通常のインタフェース
Comparatorインタフェースのcompareメソッドは引数が2つ、戻り値はint型です。 その2つを比較し、以下のように返す必要があります。
- 第一引数が先:負の数
- 同じ:0
- 第二引数が先:正の数
これは整数なら「第一引数 - 第二引数」で求めることが出来ます。逆順(降順)にしたい場合、「第二引数 - 第一引数」で求められます。
Comparatorインタフェースを実装すると、以下のようになります(昇順の場合)。
class MyComparator implements Comparator<Integer>{
public int compare(Integer a, Integer b) {
return a - b;
}
}
Arrays.sortではこれをnewして渡します。
Arrays.sort(nums, new MyComparator());
匿名クラス
このように、インタフェースを実装するには新たなクラスを作り、実装する必要があります。
しかし、一度しか使用しない場合など、わざわざクラスを定義するまでもない場合、引数に直接クラスの実装を書くことが出来ます。名前を付けずにクラスを作るので、匿名クラスと呼びます。
匿名クラスは以下のように書きます。
new インタフェース名(){
インタフェースを実装したクラスの中身
}
Comparatorの例を書き直してみます。
Arrays.sort(nums, new Comparator<Integer>(){
public int compare(Integer a, Integer b) {
return a - b;
}
});
ラムダ式
インタフェースで実装しなければならないメソッドが1つだけであれば、ラムダ式を使うことが出来ます。
ラムダ式を使う場合、インタフェースを実装したクラスを作る必要はありません。 必要になるメソッドだけ(今回はcompareメソッド)を以下の形で渡します。
(引数,,)-> 処理内容
つまり、以下のようになります。
Arrays.sort(nums, (Integer a, Integer b)-> { return a - b; } );
なお、引数は型を省略できます。変数名だけでかまいません。
Arrays.sort(nums, (a, b)-> { return a - b; } );
さらに、{}を省略することができます。そのときには、return は省略します。
Arrays.sort(nums, (a, b)-> a - b );
これにより、インタフェースを実装したクラスを作ってnewしたことと同じことになります。
Listの場合
Listの整列にもsortメソッドが使用できます。Collectionsクラスのsortメソッドで同じように Comparatorインタフェースを使用します。 これもラムダ式で書くことが出来ます。
// リストの初期化
List<Integer> list = Arrays.asList(20, 15, 12, 18);
// ラムダ式を使った整列
Collections.sort(list, (a,b)-> a - b );
// 表示
System.out.println(list);