JavaのInterfaceではGetter・Setterの自動生成はできないの？

# はじめに

結論から言うと、インターフェースではGetter・Setterの自動生成はでません。インターフェースの性質を理解していれば、当たり前なのですが、個人的に混乱したので、まとめます。



開発環境は以下の通りです。

- jdk 1.8.0_172
- Lombok 1.18.2



# getter, setterのコピペはバグの温床

Javaのコーディングではクラスを頻繁に作ると思います。その度に毎回、以下のようなgetter, setter を定義している人は多いのではないでしょうか？（少なくとも私はそうでした）

```java
// 普通のクラス
public class SampleClass {
	// メンバ変数
	private String foo;

	// Getter
	public String getFoo() {
		return this.foo;
	}

	// Setter
	public void setFoo(String foo) {
		this.foo = foo;
	}
}
```

```java
// 呼び出し元
public void SampleMethod {
	// 普通のクラス
	SampleClass sample1 = new SampleClass();
	sample1.setFoo("hoge");
	System.out.println("sample1.getFoo(): " + sample1.getFoo());
}
```

例えば、クラスやメンバ変数（フィールド）が大量にあるとかで、こういうgetterみたいな単純なメソッドを大量にコーディングしなければならない場合、多くの人がコピペすると思います。

こういうコピペって、ミスしても気づきにくいので、バグの温床になりやすいと思います。



# クラスに@Dataをつけると？

それを解決してくれるのが、Lombokです。以下のように書くだけで、getterやsetterを自動生成してくれます。（C#のプロパティみたいなもの）

```java
import lombok.Data;

// クラスに@Dataをつける
@Data
public class SampleClassWithLombok {
	// メンバ変数
	private String foo;
}
```

```java
// 呼び出し元
public void SampleMethod {
	// @Dataのついたクラス
	SampleClassWithLombok sample2 = new SampleClassWithLombok();
	sample2.setFoo("hoge");
	System.out.println("sample2.getFoo(): " + sample2.getFoo());
}
```

これで、コード量を減らせて、バグの温床もつぶすことができました。

Lombokの導入方法は、以前、こちらにまとめましたので、ご参照ください。

- [WindowsにSpring Tool Suiteを導入する](https://qiita.com/segur/items/4cd283d9763a1953f336)
- [MacにSpring Tool Suiteを導入する](https://qiita.com/segur/items/f9d7b5cdbc02531ffbb0)



# インターフェースに@Dataをつけると？

ここで、疑問に思ったのが、インターフェースに`@Data`を付けるとどうなるのか？ということです。

インターフェースのメンバ変数には`private`を指定することができないので、`public`なメンバ変数にgetter, setterをつけてみたいと思います。（意味はないですが）

こんな感じのインターフェースに@Dataをつけてみます。

```java
// インターフェースに@Dataをつける
@Data
public interface SampleInterface {
	// メンバ変数
	public String bar = "bar";
}
```

つけた途端にEclipseが`@Data is only supported on a class.`というエラーを吐きました。

そもそもインターフェースのメンバ変数は定数なので、setterというものを定義できないのが原因だと思います。



# 実装クラスに@Dataをつけると？

実装クラスではどうなのでしょうか？こんなインターフェースと実装クラスがあるとします。

```java
// インターフェース
public interface SampleInterface {
}
```

```java
import lombok.Data;

// 実装Classに@Dataをつける
@Data
public class SampleImpl implements SampleInterface {
	// メンバ変数
	private String foo;
}
```

```java
// 呼び出し元
public void SampleMethod {
	// @Dataのついた実装Class
	SampleInterface sample3 = new SampleImpl();
	sample3.setFoo("hoge");
	System.out.println("sample3.getFoo(): " + sample3.getFoo());
}
```

こんな感じのコードを書いてみたところ、インターフェース・実装クラスでエラーは発生しませんでしたが、呼び出し元で`メソッド setFoo(String) は型 SampleInterface で未定義です`というエラーが発生しました。

実装クラスにgetter, setterは定義されているようですが、インターフェースにその定義がないため、エラーになったようです。

ここで、インターフェースにgetter, setterを追加してみました。

```java
// インターフェースにgetter, setterを定義する
public interface SampleInterface {
	// Getter
	public String getFoo();

	// Setter
	public void setFoo(String foo);
}
```

これでエラーは出なくなりました。しかし、インターフェースにgetter, setterを定義する羽目になりました。これでは、コピペミスを抑制することができませんね。



# 抽象クラスに@Dataをつけると？

抽象クラスではどうなのでしょうか？こんな抽象クラスと継承クラスがあるとします。

```java
import lombok.Data;

// 抽象Classに@Dataをつける
@Data
public abstract class SampleAbstract {
	// メンバ変数
	private String foo;
}
```

```java
//継承Class
public class SampleExtends extends SampleAbstract {
}
```

```java
// 呼び出し元
public void SampleMethod {
	// @Dataのついた抽象Class
	SampleAbstract sample4 = new SampleExtends();
	sample4.setFoo("hoge");
	System.out.println("sample4.getFoo(): " + sample4.getFoo());
}
```

こんな感じのコードを書いてみたところ、エラーは発生しませんでした。インターフェースと違って、抽象クラスは`private`なメンバ変数を持つことができるので、getter, setterも自動定義できるのかもしれませんね。



# さいごに

通常のクラス・実装クラス・抽象クラスは、`@Data`をつけることで、メンバ変数のgetter, setterを自動定義することができます。

しかし、インターフェースは、手動でgetter, setterを定義する必要があることがわかりました。

抽象クラスに切り替えれば、お手軽に回避できると思いますが、そもそもインターフェースにgetter, setterが必要になった時点で、一旦、そのインターフェースの設計を見直した方がよいのかもしれません。