web-dev-qa-db-ja.com

Java 8ラムダVoid引数

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型パラメータを取り除く方法はありますか?

144
Wickoo

RunnableAction<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"));
89
Matt

何もしないが何かを返す場合は Supplier を使用してください。

何かを取るが何も返さない場合は、 Consumer を使用してください。

結果が返されてスローされる可能性がある場合は Callable を使用します(一般的なCS用語では Thunk に最も近い)。

どちらも実行せずにスローできない場合は、 Runnable を使用してください。

372
x1a0

ラムダ:

() -> { System.out.println("Do nothing!"); };

実際には、次のようなインターフェースの実装を表します。

public interface Something {
    void action();
}

これはあなたが定義したものとは全く異なります。それがあなたがエラーを受け取る理由です。

あなたはあなたの@FunctionalInterfaceを拡張することも、まったく新しいものを紹介することもできないので、それで私はあなたには多くの選択肢がないと思います。ただし、Optional<T>インターフェースを使用して、一部の値(戻り型またはメソッドパラメータ)が欠落していることを示すことができます。しかし、これではラムダボディは単純になりません。

36

その特別な場合のためにサブインターフェースを作成することができます。

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!");
28
Jordão

それは不可能です。 (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));
5
fabian

あなたの機能的なインターフェースの中に静的メソッドを追加する

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!
4
MCHAppy

参考のために、メソッドが値をスローおよび/または返す場合に、どの機能インターフェースをメソッド参照に使用できるかを示します。

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
}
3
SlavaL

関数定義があなたの例では一致しないので、私はそれが可能だとは思わない。

あなたのラムダ式は正確に以下のように評価されます。

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文または引数がないと、コンパイラエラーが発生します。

したがって、引数を取り、それを返す関数を宣言すると、上記のどちらでもない関数に変換することは不可能だと思います。

3
pnadczuk