Java 8には次のような機能的なインターフェースがあるとしましょう。
interface Action<T, U> {
U execute(T t);
}
そして場合によっては、引数や戻り値のないアクションが必要です。だから私はこのようなものを書く:
Action<Void, Void> a = () -> { System.out.println("Do nothing!"); };
しかし、それは私にコンパイルエラーを与えます、私はそれを書く必要があります
Action<Void, Void> a = (Void v) -> { System.out.println("Do nothing!"); return null;};
これは醜いです。 Void
型パラメータを取り除く方法はありますか?
Runnable
をAction<Void, Void>
に変換する小さなヘルパー関数を使うことで、後に続く構文が可能になります(例えばAction
に置くことができます)。
public static Action<Void, Void> action(Runnable runnable) {
return (v) -> {
runnable.run();
return null;
};
}
// Somewhere else in your code
Action<Void, Void> action = action(() -> System.out.println("foo"));
ラムダ:
() -> { System.out.println("Do nothing!"); };
実際には、次のようなインターフェースの実装を表します。
public interface Something {
void action();
}
これはあなたが定義したものとは全く異なります。それがあなたがエラーを受け取る理由です。
あなたはあなたの@FunctionalInterface
を拡張することも、まったく新しいものを紹介することもできないので、それで私はあなたには多くの選択肢がないと思います。ただし、Optional<T>
インターフェースを使用して、一部の値(戻り型またはメソッドパラメータ)が欠落していることを示すことができます。しかし、これではラムダボディは単純になりません。
その特別な場合のためにサブインターフェースを作成することができます。
interface Command extends Action<Void, Void> {
default Void execute(Void v) {
execute();
return null;
}
void execute();
}
継承されたパラメータ化メソッドVoid execute(Void)
をオーバーライドするために、 デフォルトメソッド を使用し、呼び出しをより単純なメソッドvoid execute()
に委任します。
その結果、使いやすくなりました。
Command c = () -> System.out.println("Do nothing!");
それは不可能です。 (Void
であっても)無効でない戻り型を持つ関数は値を返さなければなりません。ただし、Action
に静的メソッドを追加して、Action
を「作成」することができます。
interface Action<T, U> {
U execute(T t);
public static Action<Void, Void> create(Runnable r) {
return (t) -> {r.run(); return null;};
}
public static <T, U> Action<T, U> create(Action<T, U> action) {
return action;
}
}
それはあなたが以下を書くことを可能にするでしょう:
// create action from Runnable
Action.create(()-> System.out.println("Hello World")).execute(null);
// create normal action
System.out.println(Action.create((Integer i) -> "number: " + i).execute(100));
あなたの機能的なインターフェースの中に静的メソッドを追加する
package example;
interface Action<T, U> {
U execute(T t);
static Action<Void,Void> invoke(Runnable runnable){
return (v) -> {
runnable.run();
return null;
};
}
}
public class Lambda {
public static void main(String[] args) {
Action<Void, Void> a = Action.invoke(() -> System.out.println("Do nothing!"));
Void t = null;
a.execute(t);
}
}
出力
Do nothing!
参考のために、メソッドが値をスローおよび/または返す場合に、どの機能インターフェースをメソッド参照に使用できるかを示します。
void notReturnsNotThrows() {};
void notReturnsThrows() throws Exception {}
String returnsNotThrows() { return ""; }
String returnsThrows() throws Exception { return ""; }
{
Runnable r1 = this::notReturnsNotThrows; //ok
Runnable r2 = this::notReturnsThrows; //error
Runnable r3 = this::returnsNotThrows; //ok
Runnable r4 = this::returnsThrows; //error
Callable c1 = this::notReturnsNotThrows; //error
Callable c2 = this::notReturnsThrows; //error
Callable c3 = this::returnsNotThrows; //ok
Callable c4 = this::returnsThrows; //ok
}
interface VoidCallableExtendsCallable extends Callable<Void> {
@Override
Void call() throws Exception;
}
interface VoidCallable {
void call() throws Exception;
}
{
VoidCallableExtendsCallable vcec1 = this::notReturnsNotThrows; //error
VoidCallableExtendsCallable vcec2 = this::notReturnsThrows; //error
VoidCallableExtendsCallable vcec3 = this::returnsNotThrows; //error
VoidCallableExtendsCallable vcec4 = this::returnsThrows; //error
VoidCallable vc1 = this::notReturnsNotThrows; //ok
VoidCallable vc2 = this::notReturnsThrows; //ok
VoidCallable vc3 = this::returnsNotThrows; //ok
VoidCallable vc4 = this::returnsThrows; //ok
}
関数定義があなたの例では一致しないので、私はそれが可能だとは思わない。
あなたのラムダ式は正確に以下のように評価されます。
void action() { }
宣言は次のようになります
Void action(Void v) {
//must return Void type.
}
例として、次のようなインタフェースがある場合
public interface VoidInterface {
public Void action(Void v);
}
互換性があることになる(インスタンス化中の)唯一の関数は次のようになります。
new VoidInterface() {
public Void action(Void v) {
//do something
return v;
}
}
また、return文または引数がないと、コンパイラエラーが発生します。
したがって、引数を取り、それを返す関数を宣言すると、上記のどちらでもない関数に変換することは不可能だと思います。