2015-10-07 21 views
5

私はLispのラムダ関数をよく理解しています。 JavaはLispと同じ柔軟性を持たないようです。 Javaでlambdaについて考える必要はありますか? 以下のコードを与えると、どうすればいいですか?パラメータとして任意のラムダ関数を渡して使用する方法

public class Draw { 
    GraphicsContext gc; 

    static void draw(double x, double y, double w, double h, boolean drawRect) { 
     if (drawRect) { 
      gc.fillRect(x, y, w, h); 
     } else { 
      gc.strokeRect(x, y, w, h); 
     } 
    } 

    // How do I do that? 
    static void drawWithLambda(double x, double y, double w, double h /**, lambda */) { 
     lambda(x, y, w, h); 
    } 

    public static void main(String[] args) { 
     draw(0, 0, 50, 50, false); // OK 
     drawWithLambda(0, 0, 50, 50, GraphicsContext::fillRect); // Ok? 
    } 
} 
+3

この記事をお読みください:http://stackoverflow.com/questions/13604703/how-do-i-define-a-method-which-takes-a-lambda-as-a-parameter-in-java-8 – PiotrSliwa

答えて

3

あなたはlambdaメソッドの引数は、実装の機能インターフェースの種類を指定する必要があります。この行は、メソッドGraphicsContext必見のfillRect

drawWithLambda(0, 0, 50, 50, GraphicsContext::fillRect); 

を動作させるためには

drawWithLambda(double x, double y, double w, double h, SomeFuncInterface lambda) { 
    lambda.someMethod (x, y, w, h); // someMethod is the single method that 
            // SomeFuncInterface implements 
} 

SomeFuncInterface機能インターフェイスのメソッドのシグネチャと互換性があります。

BTW、GraphicsContext::fillRectはラムダ式ではなくメソッド参照です。ラムダ式、メソッド参照、またはその他の機能インタフェースの実装(通常のクラスインスタンス、匿名クラスインスタンスなど)を渡すことができます。

+1

'GraphicsContext :: fillRect'はコンパイルされません。なぜなら、非st aticメソッド 'fillRect'です。 'gc :: fillRect'を使う必要があります。ここで' gc'は 'GraphicsContext'のインスタンスです。 – Tunaki

+1

@屯aki私の答えは一般的でした。私は 'GraphicsContext'クラスに慣れていないので、' fillRect'が静的であるかどうかわかりませんでした。 – Eran

3

JavaのLambdaは、functional interfaceという概念と組み合わせて動作します。

典型的な例はFunctionです。 Functionは、その機能的メソッドであるapplyが単一の引数をとり、結果を返すメソッドであるファンクションインタフェースです。

あなたはこのように、機能的方法4つのパラメータを取り、何の戻り値の型を持たないを定義し、独自の機能インタフェースを作成することができます。

@FunctionalInterface 
interface RectangleDrawer { 
    void draw(double x, double y, double w, double h); 
} 

FunctionalInterface注釈が必須ではありませんが、それは明確なを与えます意図)。

この機能インタフェースの契約に準拠したラムダを作成できます。典型的なlambda syntax(method arguments) -> (lambda body)です。この例では、(x, y, w, h) -> gc.fillRect(x, y, w, h)となります。これはラムダが4つの引数を宣言し、戻り値の型を持たないためコンパイルされるため、前に定義したRectangleDrawerの関数メソッドとして表すことができます。

あなたの例になるでしょう:

static GraphicsContext gc; 

public static void main(String[] args) { 
    draw(0, 0, 50, 50, gc::fillRect); 
    draw(0, 0, 50, 50, gc::strokeRect); 
} 

static void draw(double x, double y, double w, double h, RectangleDrawer drawer) { 
    drawer.draw(x, y, w, h); 
} 
:この特定のケースで

static GraphicsContext gc; 

public static void main(String[] args) { 
    draw(0, 0, 50, 50, (x, y, w, h) -> gc.fillRect(x, y, w, h)); 
    draw(0, 0, 50, 50, (x, y, w, h) -> gc.strokeRect(x, y, w, h)); 
} 

static void draw(double x, double y, double w, double h, RectangleDrawer drawer) { 
    drawer.draw(x, y, w, h); 
} 

を、より単純なコードを記述することができます::演算子を使用して、ラムダを作成するためにmethod referenceを使用することが可能です

+0

ありがとうございました。私はそれを得たと思う。私がパラメータとして渡したいすべての関数に対して、私は使用しようとしている関数と同じシグネチャを持つ一つの関数定義だけを定義している。 – user2407434

+1

@ user2407434インターアートを常に定義する必要はありません。既存のものを['java.util.function'](https://docs.oracle.com/javase/8/docs/)で使用できます。 api/java/util/function/package-summary.html)パッケージに含まれています。 – Tunaki

関連する問題