今までguavaのr09を使っていたのですが、先月末にRelease10.0が出ていたようなので早速使ってみました。
新機能として目立つのはCacheとEventBus。Cacheはなんとなく使い道が分かりそうなのでEventBusについて調べたところ、シンプルで使いやすそうなイベント駆動基盤でした。面白かったので、使い方と注意点を簡単にまとめておきます。
他のイベント駆動基盤との違い
javadocにまとまってます。
私自身は他の基盤に詳しくないので、差別化できているかどうかわかりませんでした。少なくともSwingライクなイベント処理よりはキレイに書けそうな印象です。
使い方
基本的にはこれだけです。ただしイベントやリスナーはインタフェースとして用意されているわけではありません。
リスナーはどのようなクラスでもよく、メソッドを@Subscribeアノテーションで修飾するだけで使えます。例えば以下のクラスはIntegerインスタンスをlistenするリスナーとして使えます。
import com.google.common.eventbus.Subscribe; public class IntegerListener { @Subscribe public void listen(Integer i) { System.out.println("Integer is posted."); } }
ここで注目したいのは、イベントとしてフツーのIntegerを使っていることです。このようにguavaのEventBusでは、好きな型をイベントとして扱えます。イベントの発火は以下のようになります。
import com.google.common.eventbus.EventBus; public class EventBusSample { public void postInteger() { EventBus eventBus = new EventBus(); eventBus.register(new IntegerListener()); eventBus.post(Integer.valueOf(0)); //=> "Integer is posted." } }
注意点
リスナーが@Subscribeで修飾されたメソッドを複数個持っている場合、これらが実行される順番は環境依存となります。
これはAnnotatedHandlerFinder#findAllHandlers()が呼び出すClass#getMethods()が、返り値の並び順について何も規定していないことに因ります。実際以下のサンプルコードは、OpenJDK7とMac OSXデフォルトのJDK6で異なる結果を出力します。
import com.google.common.eventbus.EventBus; import com.google.common.eventbus.Subscribe; public class EventBusSample { @Subscribe public void listen(Object i) { System.out.println("Object is posted."); } @Subscribe public void listen(Integer i) { System.out.println("Integer is posted."); } public static void main(String[] args) { new EventBusSample().execute(); } private void execute() { EventBus eventBus = new EventBus(); eventBus.register(this); eventBus.post(Integer.valueOf(0)); } }
ですのでメソッドの実行順が重要な意味を持つ場合は、同一クラス内に@Subscribeで修飾されたメソッドを複数個作らない方が良いでしょう。少なくとも特定の型とその親クラスに反応するメソッドは、1つだけに限定したほうがよさそうです。