web-dev-qa-db-ja.com

Java 8でラムダをパラメータとして取るメソッドを定義するにはどうすればよいですか?

Java 8では、メソッドはLambda式として作成でき、参照によって渡すことができます(内部で少し作業があります)。オンラインでラムダを作成してメソッドで使用する例はたくさんありますが、ラムダをパラメータとして使用してメソッドを作成する例はありません。そのための構文は何ですか?

MyClass.method((a, b) -> a+b);


class MyClass{
  //How do I define this method?
  static int method(Lambda l){
    return l(5, 10);
  }
}
302
Marius

ラムダは純粋にコールサイトの構成要素です。ラムダの受信者はラムダが関係していることを知る必要はなく、代わりに適切なメソッドを持つインタフェースを受け入れます。

言い換えれば、あなたは自分が欲しいものを正確に受け入れて返す機能的なインターフェース(つまり単一のメソッドを持つインターフェース)を定義または使用します。

このために、Java 8は Java.util.function の中でよく使われるインターフェースタイプのセットを持っています。(についてのヒントについては Maurice Naftalin に感謝JavaDoc).

この特定のユースケースでは、 Java.util.function.IntBinaryOperatorの単一のint applyAsInt(int left, int right)メソッド があるので、methodは次のように書くことができます。

static int method(IntBinaryOperator op){
    return op.applyAsInt(5, 10);
}

しかし、あなたはあなた自身のインターフェースを定義してそれをこのように使うことができます:

public interface TwoArgIntOperator {
    public int op(int a, int b);
}

//elsewhere:
static int method(TwoArgIntOperator operator) {
    return operator.op(5, 10);
}

独自のインターフェースを使用すると、意図をより明確に示す名前を付けることができるという利点があります。

209
Joachim Sauer

ラムダ式を使用するには、独自の関数型インタフェースを作成するか、2つの整数を必要とし、値として返される操作用のJava関数型インタフェースを使用する必要があります。 IntBinaryOperator

ユーザー定義機能インターフェースを使用する

interface TwoArgInterface {

    public int operation(int a, int b);
}

public class MyClass {

    public static void main(String javalatte[]) {
        // this is lambda expression
        TwoArgInterface plusOperation = (a, b) -> a + b;
        System.out.println("Sum of 10,34 : " + plusOperation.operation(10, 34));

    }
}

Java機能インターフェースの使用

import Java.util.function.IntBinaryOperator;

public class MyClass1 {

    static void main(String javalatte[]) {
        // this is lambda expression
        IntBinaryOperator plusOperation = (a, b) -> a + b;
        System.out.println("Sum of 10,34 : " + plusOperation.applyAsInt(10, 34));

    }
}

私が作成した他の例はここ です

55
pardeep131085

3つ以上のパラメータを持たない関数の場合は、独自のインタフェースを定義せずにそれらを渡すことができます。例えば、

class Klass {
  static List<String> foo(Integer a, String b) { ... }
}

class MyClass{

  static List<String> method(BiFunction<Integer, String, List<String>> fn){
    return fn.apply(5, "FooBar");
  }
}

List<String> lStr = MyClass.method((a, b) -> Klass.foo((Integer) a, (String) b));

BiFunction<Integer, String, List<String>>では、IntegerStringがそのパラメーターで、List<String>がその戻り型です。

パラメーターが1つしかない関数の場合は、Function<T, R>を使用できます。ここで、Tはそのパラメーター型で、Rは戻り値の型です。 Javaによって既に使用可能になっているすべてのインターフェースについては、この ページ を参照してください。

35
David Wu

http://lambdafaq.org/lambda-resources からリンクされている、Lambda対応のJava 8 JavaDocsのWebアクセス可能な公開版があります。 (これは明らかにJoachim Sauerの回答に対するコメントですが、コメントを追加する必要があるという評判のポイントでSOアカウントに入ることはできません。)lambdafaqサイト(私は維持します)がこれに答えますそして他にも多くのJava-λ質問があります。

NBこの答えは、Java 8 GAドキュメントが 一般に公開される になる前に書かれました。ただし、 Lambda FAQ は、Java 8で導入された機能について学ぶ人々にはまだ有用な場合があるため、そのままにしておきます。

14

これをグーグルしている人のために、良い方法はJava.util.function.BiConsumerを使うことです。例:

Import Java.util.function.Consumer
public Class Main {
    public static void runLambda(BiConsumer<Integer, Integer> lambda) {
        lambda.accept(102, 54)
    }

    public static void main(String[] args) {
        runLambda((int1, int2) -> System.out.println(int1 + " + " + int2 + " = " + (int1 + int2)));
    }

アウトプリントは以下のようになります。

5
Big_Bad_E

ラムダ式は引数として渡すことができます。ラムダ式を引数として渡すには、(ラムダ式を引数として受け取る)パラメータの型が機能インタフェース型である必要があります。

機能的なインターフェースがある場合 -

interface IMyFunc {
   boolean test(int num);
}

そして、それが5より大きい場合にのみリストにintを追加するfilterメソッドがあります。ここで、filterメソッドはパラメータの一つとして機能的なインターフェースIMyFuncを持っていることに注意してください。その場合、ラムダ式はmethodパラメータの引数として渡すことができます。

public class LambdaDemo {
    public static List<Integer> filter(IMyFunc testNum, List<Integer> listItems) {
        List<Integer> result = new ArrayList<Integer>();
        for(Integer item: listItems) {
            if(testNum.test(item)) {
                result.add(item);
            }
        }
        return result;
    }
    public static void main(String[] args) {
        List<Integer> myList = new ArrayList<Integer>();
        myList.add(1);
        myList.add(4);
        myList.add(6);
        myList.add(7);
        // calling filter method with a lambda expression
        // as one of the param
        Collection<Integer> values = filter(n -> n > 5, myList);

        System.out.println("Filtered values " + values);
    }
}
4
infoj

私にとって、最も理にかなっている解決策はCallbackインターフェースを定義することです。

interface Callback {
    void call();
}

そして、呼び出したい関数のパラメータとしてそれを使用します。

void somewhereInYourCode() {
    method(() -> {
        // You've passed a lambda!
        // method() is done, do whatever you want here.
    });
}

void method(Callback callback) {
    // Do what you have to do
    // ...

    // Don't forget to notify the caller once you're done
    callback.call();
}

ただの精度

ラムダは特別なインターフェース、クラス、あるいはあなたが自分で宣言できるものではありません。 Lambdaは、() -> {}特殊構文に付けられた名前です。これにより、単一メソッドのインターフェースをパラメーターとして渡すときの読みやすさが向上します。これを置き換えるように設計されています。

method(new Callback() {
    @Override
    public void call() {
        // Classic interface implementation, lot of useless boilerplate code.
        // method() is done, do whatever you want here.
    }
});

ですから、上の例では、Callbackラムダではなく、通常のインターフェースにすぎません。 lambdaは、それを実装するために使用できるショートカット構文の名前です。

3
flawyte

基本的にパラメータとしてラムダ式を渡すには、それを保持できる型が必要です。整数値と同じように、プリミティブintまたはIntegerクラスに保持します。 Javaはラムダ式のための別の型を持たず、代わりに引数を保持するための型としてインタフェースを使用します。しかし、そのインターフェースは機能的インターフェースであるべきです。

1
Vamshi

ラムダはオブジェクトではなく機能的インタフェースです。アノテーションとして@FuntionalInterfaceを使うことができるのと同じくらい多くの機能的インターフェースを定義することができます

@FuntionalInterface
public interface SumLambdaExpression {
     public int do(int a, int b);
}

public class MyClass {
     public static void main(String [] args) {
          SumLambdaExpression s = (a,b)->a+b;
          lambdaArgFunction(s);
     }

     public static void lambdaArgFunction(SumLambdaExpression s) {
          System.out.println("Output : "+s.do(2,5));
     }
}

出力は以下のようになります

Output : 7

ラムダ式の基本概念は、独自のロジックを定義することですが、すでに定義済みの引数を定義することです。したがって、上記のコードでは、do関数の定義を他の定義から追加するように変更できますが、引数は2に制限されています。

1
raja emani

まあ、それは簡単です。ラムダ式の目的は、関数型インタフェースを実装することです。それはただ一つのメソッドを持つインターフェースです。 これは、事前定義された機能的なインターフェースと旧来の機能的なインターフェースに関する素晴らしい記事です。

とにかく、あなたがあなた自身の機能的なインターフェースを実装したいならば、それを作りなさい。簡単な例として

public interface MyFunctionalInterface {
    String makeIt(String s);
}

それでは、クラスを作成しましょう。ここで、MyFunctionalInterfaceの型を受け入れるメソッドを作成します。

public class Main {

    static void printIt(String s, MyFunctionalInterface f) {
        System.out.println(f.makeIt(s));
    }

    public static void main(String[] args) {

    }
}

最後にすべきことは、定義したメソッドにMyFunctionalInterfaceの実装を渡すことです。

public class Main {

    static void printIt(String s, MyFunctionalInterface f) {
        System.out.println(f.makeIt(s));
    }

    public static void main(String[] args) {
        printIt("Java", s -> s + " is Awesome");
    }
}

それでおしまい!

1
SanchelliosProg