_okuno's tumblr RSS

テキトーに集めてみます。。。

Archive

Nov
12th
Wed
permalink

java Predicate

関数型プログラミング的な機能

ここまで読まれた方は、Google Collections Libraryが、かなりまともでストレスを感じさせないコレクションだと知って、これからダウンロードしてみようと考えておられるかもしれません。しか し、ちょっと待ってください。まだ、嬉しいものがあります。

Javaは関数型言語でありませんが、関数の考え方を少なくとも限定されたスコープで実に簡単に用いることができ、それによって可読性と効率を大きく高めることができます。

たとえば、自動車のリストがあり、それぞれの自動車は名前と価格を持つものと仮定します。このリストから価格の高い自動車をすべて抜き出して自動車のコレクションを作り、それをプログラムの中で調査することを考えます。

従来のやり方なら、自動車のコレクションをループで走査して価格をチェックし、価格が一定の限度を超えたら、その自動車に関する何らかの処理を実行するか、その自動車を別の新しい高価格自動車コレクションにコピーすることになるでしょう。

Google Collections Libraryには、これを別のやり方で実現するプレディケート(Predicate)という仕組みが用意されています。

プレディケート(Predicate)

プレディケートとは、クラスのインスタンスに基づいて選択基準を指定し、そのクラスに対応するインスタンスをコレクションから選択的に抽出できるようにする仕組みです。次の例を見れば、この機能がよくわかるでしょう。

final Predicate<Car> expensiveCar = new Predicate<Car>() {
public boolean apply(Car car) {
return car.price > 50000;
}
};

List<Car> cars = Lists.newArrayList();
cars.add(new Car("Ford Taurus", 20000));
cars.add(new Car("Tesla", 90000));
cars.add(new Car("Toyota Camry", 25000));
cars.add(new Car("McClaren F1", 600000));

final List<Car> premiumCars =
Lists.immutableList(Iterables.filter(cars, expensiveCar));

この例では、expensiveCarというプレディケートを作成しています。これは自動車の価格が50000を超えるとtrueを返します。プレディ ケートのapplyメソッドには選択基準を記述する必要があります。これを自動車のリストにIterables.filter()または Iterators.filter()で適用すると、premiumCarsの不変リスト(TeslaとMcLaren F1のみを含む)が作られます。

Javaの内部クラスの構文のインパクトが薄れる面はありますが、関数的な処理としては、かなりエレガントです(プレディケートをインラインで定義しよ うとすると、無名内部クラスの構文を使う必要があります)。Java 7ではクロージャがいくつか提案されており、それを使えば、もっと簡潔に書けるでしょう。いずれにせよ、この簡単な例だけでははっきりしませんが、コード がもっと複雑になれば、ループを使った方法よりもずっと簡潔で可読性が高くなることがわかるはずです。