関数型インターフェースで気になったことを試してみた
関数型インターフェースとは?
ざっくり言うと、メソッドが1つだけ定義されたインターフェース。
関数型にならないケース
メソッド1つだけと言っても、defaultやstaticは対象外。
なので、defaultメソッドだけ持ったインターフェースは関数インターフェースと呼べない。
@FunctionalInterface
public interface A {
default public int onlyMethod(int value) {
return origin * 2;
};
}
エラーメッセージはこんな感じ。
予期しない@FunctionalInterface注釈
Aは機能インタフェースではありません
インタフェース Aで抽象メソッドが見つかりません
てか、関数型インターフェースって名前じゃないのか!
機械翻訳な気もするけど、Oracle公式は機能インターフェースなんですかねぇ。
関数型インターフェースと継承
関数型インターフェースを継承しても、メソッドが1つだけなら関数型インターフェースを名乗れる。
使いドコロは・・・ないと思うけど。
@FunctionalInterface
public interface A {
int onlyMethod(int value);
}
@FunctionalInterface
public interface B extends A{
// コンパイルエラーにならない。
}
当然ですけど、default修飾子付きのメソッドでオーバーライドするとコンパイルエラーです。
エラーメッセージは最初と同じで抽象メソッドが見つからないという内容です。
@FunctionalInterface
public interface C extends A{
@Override
default int onlyMethod(int value) {
return 0;
};
}
なお、@FunctionalInterfaceを外せばコンパイルは通ります。
それによって、インターフェースの抽象メソッドをインターフェースが実装するという謎なインターフェースが出来上がります。
継承(逆の場合)
関数型ではないインターフェースを継承して無理やり関数型にしてしまう。
public interface A {
default int onlyMethod(int value) {
return 0;
};
}
@FunctionalInterface
public interface B extends A{
int onlyMethod(int value);
}
デフォルトの実装を全く無視する荒業。
使い道あるかは知らぬ・・・。
多重継承
複数のインターフェースを継承した場合のパターンも試してみました。
まずはコンパイルエラーにならないパターン。
@FunctionalInterface
public interface A1 {
int onlyMethod(int value);
}
@FunctionalInterface
public interface A2 {
int onlyMethod(int value);
}
@FunctionalInterface
public interface B extends A1, A2 {
// コンパイルエラーにならない。
}
当然、継承するインターフェースのメソッドの定義が違えばコンパイルエラーになります。
@FunctionalInterface
public interface A1 {
int mainMethod(int value);
}
@FunctionalInterface
public interface A2 {
int subMethod(int value);
}
@FunctionalInterface
public interface B extends A1, A2 {
// これはコンパイルエラー。
}
ちなみにエラーメッセージはこんな感じ。
予期しない@FunctionalInterface注釈
Bは機能インタフェースではありません
インタフェース Bで複数のオーバーライドしない抽象メソッドが見つかりました
この場合、どちらかのメソッドを実装すればBを関数型インターフェースにすることができます。
@FunctionalInterface
public interface B extends A1 , A2 {
@Override
default int subMethod(int value) {
return 1;
};
}
やっぱり使いドコロが無さそうですが、あえて使うならこんな感じだと思います。
@FunctionalInterface
public interface C extends A , B{
@Override
default int subMethod(int value) {
// デフォルトと言いつつ実装を強要してみる
throw new UnsupportedOperationException();
};
}
ここまでして関数型インターフェースを作りたい男の人って・・・。
まとめ
Lambdaに付随して言語仕様がガッツリ変わっているおかげで、インターフェース周りで色々出来て面白いです。
ただ、きちんと規約決めておかないとインターフェースに実装メソッドが大量発生したりstaticメソッドだらけになってカオスなものが出来上がる予感もします。。。