yojikのlog

yojikのブログです

Java8でDuckTyping的なこと

Javaのラムダ式のついでに導入されたメソッド参照がなかなか便利な感じです。メソッド参照をつかってDuckTyping的なことができます。

HasName という関数型インタフェースを受け入れるGreeterクラスの定義*1
public class Greeter {
  /** 関数型インタフェースの定義 */
  @FunctionalInterface
  interface HasName { String getName();}
  
  /** 「名前を持っているオブジェクトに挨拶をしてもらう」メソッド */
  public void greet(HasName... targets) {
        for(HasName it : targets) {
            System.out.println(it.getName());
        };
  }
}
「HasNameの関数型インタフェースと同じシグネチャを持つメソッド」を持つクラスの定義

ただし引数と戻り値さえあっていれば、HasNameインタフェースを実装する必要もないし、名前をあわせる必要も無いです。

class Duck {
    public String name() {
        return "duck";
    }
}
class Dog {
    public String myname() {
        return "dog";
    }
}
Greeter::greetメソッドにメソッド参照を渡す

DuckやDogのインスタンスからメソッド参照を取りだしgreetメソッドに渡す。メソッドの引数戻り値さえあっていればどんなクラス/インスタンスのメソッドでも渡すことができます。

もちろんクロージャにおける「環境」のように、インスタンスの情報*2も一緒についていきます。*3

public class Sample {
    public static void main(String[] args) {
        Greeter  g = new Greeter();
        Duck duck= new Duck();
        Dog dog  = new Dog();
        g.greet(duck::name, dog::myname);
    }
}

*1:@FunctionalInterfaceアノテーションは無くても別にいいですが、書いておくと定義が関数型インタフェースに沿っているかチェックしてくれます

*2:この場合ならduckやdogのインスタンス変数の情報。定義してないけど

*3:メソッド参照に対応するインスタンスのクラスはSample$$Lambda$数字 という名前になるようです。なおコンパイル時ではなく動的に生成されている模様