沈思黙考：自分で作る関数に関数型インタフェースを活かす方法(java)

## 初めに

streamなどでラムダ式を使うことはできても、自分で作る関数に関数型インタフェースを活かすことができない方がいるかもしれない。
そんな方にむけて、簡単な例を使って、自作関数への関数型インタフェースの適用方法を紹介したいと思う。

## 例題

あるオブジェクトのプロパティを別のプロパティにコピーすることは、よくあることだろう。
その際、プロパティの値がnullでない場合だけ、コピーするという条件がつくこともよくあることだ。
そして、この例題のように、様々な型プロパティのコピーがずらっと並ぶこともよくある。
このようにコピペで対応してもよい場合もあるだろうが、少し工夫をしたい。
次のコードに対し、共通関数を作って呼び出しを簡素化しよう。
なお、getName()はStringを返し、setName()は、Stringをセットする。
getFlag()はBooleanを返し、setFlag()は、Booleanをセットする。

```java
if(objA.getName()!=null) {
    objB.setName(objA.getName());
}
if(objA.getFlag()!=null) {
    objB.setFlag(objA.getFlag());
}
```

## 疑似コード

以下のように書けるといいですね。
javaではどのよにして実現するか見ていきましょう。

```java
setIfNotNull(value,func) {
    if(value!= null) {
        func(value);
    }
}
setIfNotNull(objA.getName(),objB.setName);
setIfNotNull(objA.getFlag(),objB.setFlag);
```

## インターフェースを使った回答(うまくいかない例)

上記疑似コードでfuncはメソッドを示していますが、javaではどのように表現すればよいでしょうか？
メソッドを示すものといえば、インターフェイスです。ここでもインターフェイスを使えば実現できるかもしれません。

```java
public interface SetNameInterface {
    void setName(String value);
}

public Class ObjB implements  SetNameInterface{
    void setName(String name);
}

public void setIfNotNull(String value,SetNameInterface obj) {
    if(value!= null) {
        obj.setName(value);
    }
}

setIfNotNull(objA.getName(),objB);

```
setName()には対応できましたが、setFlag()には対応できないのは明らかです。
この方法は直観的ですが、うまくいきません。

## インターフェースを使った回答(うまくいくが冗長)

setName()とsetFlag()をsetIfNotNull()からは、共通の関数名funcで呼び出したいのだから、
funcをインターフェイスとしてもつオブジェクトをsetName()とsetFlag()に対して持たせるのはどうでしょうか？

```java

public Class ObjB {
	public void setName(String name) {
		System.out.println("OnjB.setName:"+name);
	}
	public void setFlag(Boolean flag) {
		System.out.println("OnjB.setFlag:"+flag);
	}
}

public interface FuncInterface<T> {
    void func(T value);
}

public class ObjBSetName implements FuncInterface<String> {
	ObjB obj;
	public ObjBSetName(ObjB obj) {
		this.obj = obj;
	}
	@Override
	public void func(String value) {
		obj.setName(value);
	}
}

public class ObjBSetFlag implements FuncInterface<Boolean> {
	ObjB obj;
	public ObjBSetFlag(ObjB obj) {
		this.obj = obj;
	}
	@Override
	public void func(Boolean value) {
		obj.setFlag(value);
	}
}

public <T>void setIfNotNull(T value,FuncInterface<T> obj) {
    if(value!= null) {
        obj.func(value);
    }
}

setIfNotNull(objA.getName(),new ObjBSetName(objB));
setIfNotNull(objA.getFlag(),new ObjBSetFlag(objB));

```

ObjBSetName ,ObjBSetFlag は、ともにFuncInterfaceインターフェースで定義されてるfunc関数を持ち、
func関数が呼び出されるとそれぞれの本来の処理objB.setName()やobjB.setFlag()を呼び出しています。
なお、FuncInterfaceインターフェースは、メソッドに渡すパラメータの型を総称型(ここではT)で宣言しており、
それに合わせて、setIfNotNull()もvalueおよびobjを総称型を使うように変更します。

## 匿名クラスを使った回答

これでやりたいことは実現できたのですが、ObjBSetName、ObjBSetFlagを用意するところが冗長です。
匿名クラスを使ってみましょう。

匿名クラスの書き方は、

> new 親クラスまたはインターフェイス名() {
>     匿名クラスの内容 (フィールドやメソッドの定義)
> };

であるので、

```java
    var objBSetName = new FuncInterface<String>() {
        @Override
        public void func(String value) {
            objB.setName(value);
        }
    };
    var objBSetFlag = new FuncInterface<Boolean>() {
        @Override
        public void func(Boolean value) {
            objB.setFlag(value);
        }
    };

```
と書けて、
呼び出しは、

```java
    setIfNotNull(objA.getName(),objBSetName);
    setIfNotNull(objA.getFlag(),objBSetFlag);
```
となります。匿名クラスの中では、オブジェクトobjBを直接参照できます。

## ラムダ式を使った回答

関数が1つだけ定義されているインターフェースの場合、匿名クラスをラムダ式に置き換えられるので、

```java
    FuncInterface<String> objBSetName = (v) -> objB.setName(v);
    FuncInterface<Boolean> objBSetFlag = (v) -> objB.setFlag(v);

```

と書き換えできる。ラムダ式には、funcという表記はないが、FuncInterfaceで定義されているfuncを実装しています。
ラムダ式には、funcが消えているのがわかりにくい点ですが、匿名クラスとよく見比べれば理解できるでしょう。

さらに変数を省略して、

```java
    setIfNotNull(objA.getName(),(v) -> objB.setName(v));
    setIfNotNull(objA.getFlag(),(v) -> objB.setFlag(v));
```

とまとめることができます。

## 関数型インタフェースを使った回答

さて、FuncInterfaceというインターフェースの宣言ですが、実は、関数型インタフェースとして
すでにConsumerが存在しますので、こちらと置き換えてしまいましょう。
(インターフェースを自作する前に提供されている関数型インタフェースが使えないか調べるとよいでしょう)

```java
public <T>void setIfNotNull(T value,Consumer<T> obj) {
    if(value!= null) {
        obj.accept(value);
    }
}
```

さらに、引数が1つですので、呼び出しは、メソッド参照を使って、

```java
    setIfNotNull(objA.getName(),objB::setName);
    setIfNotNull(objA.getFlag(),objB::setFlag);
```

となります。
かなりすっきりしましたね。

## まとめ

今回は、小さな例で説明しましたが、「処理」を関数に渡すことができる、ということがおわかりいただけた
と思います。そのための宣言が「関数型インタフェース」です。
これを使えば、「Strategy パターン」を実現できるというもは、すでに想像されていることでしょう。
ぜひあなたのプログラムにも適用して、プログラムの再利用を図ってください。