Java 8ラムダVoid引数


188

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



7
定義したとおりにアクションが必要な場合、それは不可能です。ただし、最初の例はRunnable、探しているに収まる可能性がありますRunnable r = () -> System.out.println("Do nothing!");
AlexisC。

1
@BobTheBuilderその投稿で提案されているように、コンシューマを使用したくありません。
Wickoo 2015

2
マットの答えは型を機能させますが、呼び出し側がnullの戻り値を取得するとどうなりますか?
Stuart Marks

8
この投稿の提案2と3がJava 9で受け入れられることを期待してください。
アッシリア2015

回答:


110

あなたは後にしている構文は、変換の小さなヘルパー関数で可能である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"));

4
これは、あなたが+1そう(またはインタフェース自体の静的メソッドで)、IMO、得ることができる回避最もクリーンである
アレクシスC.

以下のKonstantin Yovkovのソリューション(@FunctionalInterfaceを使用)は、ジェネリックを含まず、追加のコードを必要としないため、より優れたソリューションです。
uthomas

@uthomas申し訳ありませんが、に関する回答はありません@FunctionalInterface。彼は単にそれを拡張することは不可能だと言っています...
Matt

1
こんにちは、@マット、申し訳ありません。反応が速すぎました。与えられた質問に対してあなたが答えることは完全に有効です。残念ながら、私の投票はロックされているため、この回答で-1を削除することはできません。2つの注意事項:1. Runnableアクションの代わりに@FunctionalInterfaceと呼ばれるカスタムの何かを実行SideEffectする必要があります。
uthomas

530

Supplier何も取らないが何かを返す場合に使用します。

Consumer何かをとるが何も返さない場合に使用します。

Callable結果を返し、スローする可能性がある場合に使用します(Thunk一般的なCS用語とほとんど同じです)。

Runnableどちらも行わず、スローできない場合に使用します。


例として、 "void"リターンコールをラップするためにこれを行いましたpublic static void wrapCall(Runnable r) { r.run(); }。ありがとう
Maxence

13
美しい答え。短くて正確。
クリントイーストウッド

残念ながら、チェック例外をスローする必要がある場合は役に立ちません。
Jesse Glick

13
この回答の完了として、編集する価値はありません。BiConsumer(テイク2、0を返す)、Function(テイク1、1を返す)、BiFunction(テイク2、1を返す)も使用できます。知っておくべき最も重要なこと
CLOVIS 2018

2
Callable(call()メソッドで例外をスローする)のようなものはありますか?戻り値は必要ですか?
dpelisek

40

ラムダ:

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

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

public interface Something {
    void action();
}

これは、定義したものとは完全に異なります。そのため、エラーが発生します。

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


問題は、Something関数が私のActionタイプのサブタイプになることはできず、2つの異なるタイプを持つことはできないということです。
Wickoo 2015

技術的にはできるが、それは避けたいと彼は言った。:)
Konstantin Yovkov 2015

31

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

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!");

このAction <Void、Void>はどこから来ていますか?SwingインターフェースもJAX-WX Actionインターフェースもそのような一般的なインターフェースはありませんか?
luis.espinal

1
@ luis.espinal:Action<T, U>は質問で宣言されています.....
ジョルダン

ははは、どうやってそれを逃したの?ありがとう!
luis.espinal

6

この表は短くて便利だと思います:

Supplier       ()    -> x
Consumer       x     -> ()
Callable       ()    -> x throws ex
Runnable       ()    -> ()
Function       x     -> y
BiFunction     x,y   -> z
Predicate      x     -> boolean
UnaryOperator  x1    -> x2
BinaryOperator x1,x2 -> x3

他の回答で述べたように、この問題の適切なオプションは Runnable


5

それは不可能です。void以外の戻り値の型を持つ関数は、それがであっても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));

4

関数型インターフェース内に静的メソッドを追加する

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!

3

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

ラムダ式は次のように正確に評価されます

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

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

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
}

もう少しコンテキストを追加してください。これは興味深いように見えますが、その意味はすぐにはわかりません。
bnieland 2018
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.